Lightning component attributes are used to pass data into a component. The attribute can a basic type (string, number, boolean), object, collection, etc. I have a React background and am used to passing callbacks as component attributes. Is there a way to pass a function type into a Lightning component?
I’m thinking something like this:
<aura:attribute name="getSuggestions" required="true" type="Function" description="Callback to get the suggestions to display to the user" />
EDIT:
Here’s an example of
<ui:button />
. The callbackc.save
is passed to the press attribute.<ui:button label="Save" class="slds-button" press="{!c.save}"/>
Say I want to create my own implementation of
<ui:button />
calledmyButton
. I would never do this in practice, but it provides a good example of passing a callback to a child component.In my custom button, I have declared three attributes: label, class, and press. I want to know how to implement the press attribute. The example below doesn’t work.
myButton.cmp:
<aura:component> <aura:attribute name="label" required="true" type="String" /> <aura:attribute name="class" required="false" type="String" /> <aura:attribute name="press" required="true" type="Object" /> <input type="button" value="{!v.label}" class="{!v.class}" onclick="{!c.onClick}" /> </aura:component>
myButtonController.js:
({ onClick : function(component, event, helper) { // Do some cross-cutting action like track button clicks. helper.trackButtonClick(component, event); var press = component.get('v.press'); press(); // This won't work because it's not a function. But it should be! I passed it a function! } })
myButtonConsumer.cmp
<aura:component> <c:myButton label="OK" class="slds-button" press="{!c.onOk}" /> </aura:component>
myButtonConsumerController.js
({ onOk: function() { alert('OK pressed!'); } })
I pass the function
c.onOk
to the press attribute, but when I invokecomponent.get('v.press')
, it doesn’t return a function. It seems like the Lightning framework wraps it somehow. How do I get at the inner value and execute it?Or perhaps there’s a better way to implement this?
Answer
The solution is to declare an event instead of an attribute when you want to provide a callback. Below is myButton.cmp rewritten to use events.
pressEvent.evt
<aura:event type="COMPONENT" />
myButton.cmp
<aura:component>
<aura:attribute name="label" required="true" type="String" />
<aura:attribute name="class" required="false" type="String" />
<!-- Declare an "instance" of pressEvent -->
<aura:registerEvent name="press" type="c:pressEvent"/>
<input type="button" value="{!v.label}" class="{!v.class}" onclick="{!c.onClick}" />
</aura:component>
myButtonController.js
({
onClick : function(component, event, helper) {
helper.trackButtonClick(component, event);
var event = component.getEvent('press');
event.fire();
}
})
This wasn’t clear from the documentation, but there are two ways to handle an event. The first is to use the <aura:handler />
markup. To handle the press event of myButton, you could do this:
<aura:handler name="press" event="c:pressEvent" action="{!c.onOk}"/>
I would avoid this approach because if you have more than one button, the press event for all of them would be handled by the same action c.onOk
.
The second way to handle an event is to pass a callback as an attribute in the <c:myButton />
markup. I didn’t see this in the Salesforce docs but found it in an unrelated question. This is exactly what I needed. Each instance of myButton gets a unique callback.
myButtonConsumer.cmp
<aura:component>
<!-- No aura:handler necessary. Just pass the callback as an attribute -->
<!--<aura:handler name="press" event="c:pressEvent" action="{!c.onOk}"/>-->
<c:myButton label="OK" class="slds-button" press="{!c.onOk}" />
<c:myButton label="Cancel" class="slds-button" press="{!c.onCancel}" />
</aura:component>
myButtonConsumerController.js
({
onOk: function(component, event) {
alert('OK pressed!');
},
onCancel: function(component, event) {
alert('Cancel pressed!');
}
})
Attribution
Source : Link , Question Author : Joe B , Answer Author : Community