Tweet |
Introduction
One of the common challenges in Visualforce involved communication between pages and components, or components and components. Solutions typically involved passing controller instances as attributes, preferably wrapped up in an interface to avoid directly coupling presentation items to specific Apex classes. This allowed a component to execute a callback in the related component/page controller, but only in response to a postback, as JavaScript remoting or Rest API is stateless and wouldn’t have access to the controller passed in as an attribute.
Lightning Application Events
Lightning components simplify this enormously via the application events functionality. This allows components/applications to fire events that are consumed by other components that subscribe to them - publish and subscribe in all its glory.
To give a simple and useless example, I have an application that allows a user to enter a search term:
and when the search term is entered, display an unhelpful message about it;
The Event
The markup for the event is pretty simple:
<aura:event type="APPLICATION" description="Search Event"> <aura:attribute name="term" type="String" /> </aura:event>
this event takes a single attribute - the string that has been searched for.
Search Component
The search component declares that it fires the event:
<aura:registerEvent name="SearchEvent" type="bblightning:SearchEvent" />
while the event is constructed and fired from the helper, via a controller method, when the user clicks the search button:
var searchTerm=component.get("v.term"); $A.get("e.bblightning:SearchEvent"). setParams({term: searchTerm}).fire();
“v.term” here refers to a component attribute, which backs the search term input field.
Results Component
The results component declares that it handles the event via the searched controller function:
<aura:handler event="bblightning:SearchEvent" action="{!c.searched}"/>
the searched function simply delegates handling of the event to a helper method, which generates the message to let the user know that their efforts haven’t been in vain:
searched : function(component, event) { var searchedTerm=event.getParam("term"); component.set('v.msg', 'You searched for the term [' + searchedTerm + '] - if I had an Apex controller, ' + ' I might find some matching records'); }
Putting It All Together
The actual functionality here is pretty immaterial, hence my being so dismissive of it. The important aspect is revealed when viewing the application markup:
<aura:application > <div class="padded"> <c:SearchForm /> <c:SearchResults /> </div> </aura:application>
The first component produces the form, while the second component displays the results. Note that there is nothing wiring the two components together in the markup, so I could just as easily assemble this application using the Lightning App Builder. What isn’t apparent through the markup is that all of this takes place client side and is very fast. Any future components that want to capture the search term, for logging/audit purposes for example, simply need to handle the event and be added to the application.
The full source for this marvellous application, related components and event is available in my Lighting Examples GitHub repository - look for the src/aura/Search* elements.
Nice post as usual Keir.
ReplyDeleteHi Bob,
ReplyDeleteThanks for the article. I am fairly new to Lightning and was wondering I could use your help.
I have a component called called main.cmp. Within main.cmp, I use another component called AccountDetails.cmp. AccountDetails.cmp contains a set of textboxes. What I am trying to do is that, from maincontroller.js, I am trying to get the value of a textbox from AccountDetails.cmp. When I use component.find("AccountName").get("v.value"), it always throws a null reference since component.find("AccountName") is undefined because it is a part of AccountDetails.cmp. How do I inform the maincontroller.js that the accountname text is a part of the AccountDetails.cmp? Here is a sample code
main.cmp
...
...
...
AccountDetails.cmp
....
I am able to populate all the values in the textbox to the child component but when I try to retrieve the value of any textbox from the main.cmp, it errs out. I really appreciate if you could shed some light on this.
Apologies the code that I pasted didn't get accepted
DeleteGreat post Bob!
ReplyDelete