[SalesForce] How to handle an event in a child component that is fired from a dynamically created grandchild component

I have a component that includes a child component. The child component has a button that fires showCustomModal on an overlayLibrary and the content is a dynamically created component.

Component hierarchy:

Parent
    Child
        Grandchild (Dynamically created)

The grandchild has a button that fires a component event that should be handled in the child component. The event fires, but is not handled. However, if I close the modal and re-open it and then click the button again the event is both fired and handled.

Parent component

<aura:component implements="flexipage:availableForAllPageTypes,forceCommunity:availableForAllPageTypes">
    <c:TestChild />
</aura:component>

Child Component

<aura:component >
    <aura:handler name="testEventName" event="c:TestEvent" action="{!c.handleTestEvent}" includeFacets="true"/>
    <aura:attribute name="overlay" type="Aura.Component[]" />
    <lightning:overlayLibrary aura:id="overlayLib"/>
    <lightning:button label="Open Modal" onclick="{!c.createComponent}" />
</aura:component>

Child Controller

({
    createComponent : function(component, event, helper) {
        $A.createComponent("c:TestGrandChild", 
            {
                testEventName: component.getReference('c.handleTestEvent'),
            },
            function(content, status, errorMessage) {
               if (status === "SUCCESS") {
                   component.find('overlayLib').showCustomModal({
                       header: "Test Title",
                       body: content, 
                       showCloseButton: true,
                   }).then(function (overlay) {
                        component.set('v.overlay', overlay);
                   })
                } 
            });
    },
    handleTestEvent : function(component, event, helper) {
        console.log('handled');
    }
})

Grandchild component

<aura:component >
    <aura:registerEvent name="testEventName" type="c:TestEvent" />
    <lightning:button label="Fire event" onclick="{!c.fireEvent}" />
</aura:component>

Grandchild controller

({
    fireEvent : function(component, event, helper) {
        var componentEvent = component.getEvent('testEventName');
        componentEvent.fire();
        component.destroy();
    },
})

Event

<aura:event type="COMPONENT" description="Test event" />

Best Answer

You might try instead of using component.getEvent('testEventName') in your grandchild controller, use event.getSource().

And then, when we handled the event in the parent component, we use event.getSource again.

Our example isn't directly related to yours, but here is the reference of how we are using it and it has been working whether it be in a dynamic component where it gets created with create component, or when it is being explicitly used in markup.

Event

<aura:event type="COMPONENT" description="Dispatched when a select has changed value">
    <aura:attribute name="values" type="String[]" description="Selected values" access="global" />
</aura:event>

The event getting registered on the child

<aura:registerEvent name="valueChange" type="c:SelectChange" />

The child component event method

handleChangeEvent : function(component, event) {
        var eventSource = event.getSource();
        var values = eventSource.get("v.value");
        var cmpEvent = component.getEvent("valueChange");
        cmpEvent.setParams({
            "values" : values
        });
        cmpEvent.fire();
    }

Handling the event on the parent

<aura:handler name="valueChange" event="c:SelectChange" action="{!c.handleEvent}" />

Then in the parent controller

handleEvent : function(component, event, helper) {
        var value = event.getParam("values");
        var item = event.getSource();
        item.set("v.value", value);
        component.set("v.validForm", helper.validateForm(component));
    },

Here is a link with more information on Handling Events with Client Side Controllers.

Related Topic