Saturday, 23 May 2015

Lightning Component Events

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:

Screen Shot 2015 05 23 at 17 34 39

and when the search term is entered, display an unhelpful message about it;

Screen Shot 2015 05 23 at 17 37 13

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.

Related Posts

 

4 comments:

  1. Hi Bob,
    Thanks 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.

    ReplyDelete
    Replies
    1. Apologies the code that I pasted didn't get accepted

      Delete