1

I worked on lightning component without enabling the locker services. And when I enabled the locker services, I faced an issue with the existing code.

Before enabling the locker services I use this method

//PickupLocationtooltip is aura:id of element

var ele = component.find("PickupLocationtooltip").getElement();

it was working fine. But When I enabled the locker Services, It is giving me an error "rerender threw an error in 'markup://c:AvailableCar' [component.find(...).getElement is not a function]"enter image description here

Please help me to overcome this problem. Let me know if anyone need more information on this.

The markup section : enter image description here

  • is PickupLocationtooltip aura:id of a component? – Manjot Singh May 29 '17 at 8:26
  • What do you want to achieve with this element ? – Fabien Taillon May 29 '17 at 8:32
  • yes @ManjotSingh – Tarique Shamim May 29 '17 at 8:47
  • I want to get this element so that I can edit the properties of this element @FabienTaillon – Tarique Shamim May 29 '17 at 8:48
  • @TariqueShamim Which properties you want to change? – Manjot Singh May 29 '17 at 8:54
5

if PickupLocationtooltip is a separate component, then you won't be able to access it's internals with Locker Service enabled.

What you will need to do to perform actions on this component is to either use events to communicate or define a public interface on the PickupLocationtooltip component via an aura:method

If you expose a method, you can call this method on the component and perform your dom manipulation that way - but the component can access it's own dom an no-one else's.

To define a method on the child component do this:

<aura:method name="manipulateDom" action="{!c.manipulateDom}" > 
  <aura:attribute name="param1" type="String" /> 
</aura:method>

To call this method, do this:

component.find("PickupLocationtooltip").manipulateDom("some val");

EDIT

As I can see you have a ui:outputText here, it's a standard built-in salesforce component. You cannot alter it's internals anymore.

However, you could replace it with a <div> or <span> and not notice any difference.

Perhaps just try this:

<div aura:id="PickupLocationtooltip">{!v.yourValue}</div>

Then when you want the value to change, just do this:

component.set("v.yourValue");

You should be doing this anyway - directly setting the innerHTML of components is frowned apon (and now doesn't work in many cases) in Lightning.

  • Sorry @CasparHarmer but "PickupLocationtooltip" is the aura:id of a element. – Tarique Shamim May 29 '17 at 8:52
  • 1
    Can you add this part of the markup in your question? – Caspar Harmer May 29 '17 at 8:54
  • I have added the markup sections @CasparHarmer – Tarique Shamim May 29 '17 at 8:59
  • ui:outputText IS actually a component. It's a built in ui namespace component. I'm sorry, but you can't access it's internals anymore with Locker Service. Your best best is to roll your own output text - esp if you don't need much fancy formatting, you could just use a div or span here. – Caspar Harmer May 29 '17 at 9:01
  • Is this the only way for getting it back on track or any other way. – Tarique Shamim May 29 '17 at 9:05
1

In addition to the excellent explanation provided by @CasparHarmer, here are some additional details.

Lightning is a component-based framework, and it works hard to implement the concept of encapsulation. That means the internals of a component should not be visible, only its interface. For example, the CSS of a component is scoped in a manner that it doesn't affect other components (parent and siblings).

Here, LockerService completes the encapsulation by making the component "opaque" (black box), and this is why methods like getElement() are not accessible from the outside.

In other words, the component that you retrieve:

var component2 = component.find("PickupLocationtooltip");

Only has the public API, whereas the component that you receive in a controller action, inside a component:

({
   myAction: function(component) { }
})

Behaves more like a this in the sense that it has access to all of the private API of the component.

The encapsulation is not perfect in Lightning, at least util we can leverage native web components and the shadow DOM. However, it's important to work now with the intended boundaries of encapsulation in mind. By doing so, you get all of the benefits of encapsulation:

  • Ease of maintenance (nobody relies on internal implementation)
  • Increased reusability (component has to be self-sufficient)

Now, there are three APIs we use normally to trigger something in a component:

  1. Attributes and functions is the simplest one: you declare an attribute, and you reuse it inside your component. This is achieved declaratively, so it requires no JavaScript:
    <aura:component>
        <aura:attribute name="class" type="String"/>
        <div class="{!v.class}"/>
    </aura:component>
  1. Attributes and method handler is a hybrid technique, in the sense that the consumer of your component do change an attribute declaratively or programmatically to triggers a handler:
    <aura:component>
        <aura:attribute name="class" type="String"/>
        <aura:handler name="change" value="{!v.class}" action="{!c.handleClassChange}"/>
    </aura:component>

And a controller method does the work:

({
    handleClassChange: function(component, event, helper) { 
        var newClass = event.getParam("value");
        var oldClass = event.getParam("oldValue");
        /* do something */ 
    }
})
  1. Method and method handler is a programmatic technique, in the sense that the consumer of your component must use JavaScript programmatically to trigger a handler:
    <aura:component>
        <aura:handler name="changeClass" action="{!c.handleClassChange}"/>
            <aura:attribute name="l" type="String"/>
        </aura:handler>
    </aura:component>

Again, a controller method does the work, but receives the values as “arguments”:

({
    handleClassChange: function(component, event, helper) { 
        var args = event.getParam('arguments');
        var class = args.class;
        /* do something */ 
   }
})

You can read more about these and other techniques here:

https://developer.salesforce.com/blogs/developer-relations/2017/04/lightning-inter-component-communication-patterns.html

  • 1
    Very nice explanation @JFParadis - Mine was much less elegant, although infomation provided as I got further in changed the situation somewhat... – Caspar Harmer May 29 '17 at 18:01
  • 1
    Thanks @CasparHarmer, but I very like your explanation. Sometimes being concise and to the point is better. Now, visitors have two comaptible explanations, and they can look at things from two different angles! – JF Paradis May 29 '17 at 19:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.