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:
- 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>
- 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 */
}
})
- 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