Passing action handlers to child components using Aura.Action

Last week I discovered something about Lightning Components I didn’t know about: aura:action. This is an attribute type that you can use to pass actions to a child component, in addition to the other supported attribute types, and it can be specially helpful if you want to decide at component instantiation which actions should the child component perform.

Let’s say that we have a child component like this one:

AuraActionChild.cmp

<aura:component >
    <aura:attribute name="myAction" type="Aura.Action" />
    
    <lightning:button label="Click me!" onclick="{!v.myAction}"/>
</aura:component>

And let’s say we define a parent like the next one:

AuraActionParent.cmp

<aura:component >
    <c:AuraActionChild myAction="{!c.clap}"/>
    <c:AuraActionChild myAction="{!c.jump}"/>
    <c:AuraActionChild myAction="{!c.dance}"/>
</aura:component>

AuraActionParentController.js

({
    clap : function(component, event, helper) {
        alert('I am clapping!');
    },
    jump : function(component, event, helper) {
        alert('I am jumping!');
    },
    dance : function(component, event, helper) {
        alert('I am dancing!');
    }
})

The result is the next one:

aura-action.gif

As you can see, we are defining the actions in the parent and passing them to the child at component instantiation, being able to execute a different action each time.

However you have to be very careful, as Aura.Action has some known limitations:

  • It is discouraged to use component.set() with the Aura.Action attribute types.
  • It is discouraged to use $A.enqueueAction() in the child component to enqueue the action passed to the Aura.Action attribute.

If you need to have something more dynamic, or to overcome these limitations, the recommended way would be to fire an event from the child component that is handled by the parent component to perform the required action.

Let’s implement the previous example in this way:

MyEvent.cmp

<aura:event type="COMPONENT" description="Execute action"/>

AuraActionChild2.cmp

<aura:component >
    <aura:registerEvent name="myEventInstance" type="c:myEvent"/>
    
    <lightning:button label="Click me!" onclick="{!c.fireMyEvent}"/>
</aura:component>

AuraActionChild2Controller.js

({
    fireMyEvent : function(component, event, helper) {
        var compEvent = component.getEvent("myEventInstance");
        compEvent.fire();
    }
})

AuraActionParent2.cmp

<aura:component >
    <aura:handler name="myEventInstance" event="c:MyEvent" action="{!c.handleComponentEvent}"/>
    <c:AuraActionChild2 aura:id="clapbutton"/>
    <c:AuraActionChild2 aura:id="jumpbutton"/>
    <c:AuraActionChild2 aura:id="dancebutton"/>
</aura:component>

AuraActionParent2Controller.cmp

({
    handleComponentEvent : function(component, event, helper) {
        var buttonClicked = event.getSource().getLocalId();
        if (buttonClicked === 'clapbutton')
            alert('I am clapping!');
        else if (buttonClicked === 'jumpbutton')
            alert('I am jumping!');
        else 
            alert('I am dancing!');
    }
})

As you can see in the example, in this way you will need to write some extra code, however, we have a finer degree of control, as we could for example add other event handlers dynamically or pass more information to the parent using event attributes. Also,  we are more inline with standard practices for components communication.

Here you have a git repo with the code of the examples.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s