[SalesForce] Lightning components – Prevent event bubbling from ui:checkbox to parent div

I'm facing issue with click event bubbling in Lightning.

I have div and inside of it few components including lightning checkbox and <a href> tag:

Component:

<div aura:id="container" class="slds-tree__item" onclick="{!c.onToggleExpand}">
    ...
    <aura:if isTrue="{!v.node.checkboxDisplayed}">
        <ui:inputCheckbox class="inline" aura:id="nodeCheckbox" value="{!v.node.selected}" disabled="{!!v.node.checkboxEnabled}" change="{!c.onCheckboxChange}" click="{!c.onCheckboxClick}"/>
    </aura:if>
    ...
   <a href="javascript:void(0);" onclick="{!c.onNodeClick}" tabindex="-1" role="presentation">{!v.node.name}</a>
</div>

I have handlers in controller for each function, I've simplified them for the sake of brevity:

Controller:

onToggleExpand: function(component, event, helper) {
    console.log('onToggleExpand');
}

onNodeClick: function(component, event, helper) {
    console.log('onNodeClick');
    event.stopPropagation();
}

onCheckboxChange: function(component, event, helper) {
    console.log('onCheckboxChange');
    event.stopPropagation();
}

onCheckboxClick: function(component, event, helper) {
    console.log('onCheckboxClick');
    event.stopPropagation();
    console.log('end');
}

When I click checkbox, in the console I get debugs in following order:

onCheckboxClick
end
onToggleExpand
onCheckboxChange

So, the event.stopPropagation() is totally ignored. What I suppose happens here is that click on child lightning checkbox causes onCheckboxClick handler to execute, but stopping propagation inside this method does not stop standard JS click propagation to parent div. My theory is backed up by fact that when clicking <a href> element, onNodeClick executes and the event is kept from propagating.

Does anyone had similar problems and has workaround for such problems? I could of course change ui:inputCheckbox to SLDS HTML version, but I would prefer to use Lightning components. Maybe something from Lightning that could replace <div>?

—-UPDATE:—-

I have tried with changing ui:inputCheckbox component to standard SLDS HTML <input type="checkbox"> tag. The code looks like that:

<div aura:id="container" class="slds-tree__item" onclick="{!c.onToggleExpand}">
    ...
    <div class="slds-form-element__control">
        <span class="slds-checkbox">
            <input type="checkbox" id="{!'node-checkbox-' + v.node.id}" checked="{!v.node.selected}" onchange="{!c.onCheckboxChange}" onclick="{!c.onCheckboxClick}" disabled="{!!v.node.checkboxEnabled}"/>
            ...

So standard HTML in both cases. I expect after clicking checkbox first onCheckboxClick is executed and then event is blocked from bubbling up to div element because event.stopPropagation() is used. However, that is not the case. Handlers are executed in following order:

onToggleExpand
onCheckboxClick
onCheckboxChange

WTF Lightning?

Best Answer

I still don't know why event.stopPropagation() does not work in this case, but I have solution how to fix the problem.

SLDS checkbox uses well-known CSS technique that hides <input type="checkbox"> element and shows label element that is styled with fancy images to override default checkbox look. Below the code:

<span class="slds-checkbox" onclick="{!c.onCheckboxClick}">
     <input type="checkbox" id="{!'node-checkbox-' + v.node.id}" checked="{!v.node.selected}" onchange="{!c.onCheckboxChange}" disabled="{!!v.node.checkboxEnabled}"/>
     <label class="slds-checkbox__label" for="{!'node-checkbox-' + v.node.id}">
           <span class="slds-checkbox--faux"></span>
     </label>
</span>

The trick is to put your onclick in correct place - if you do it on whole <span class="checkbox">, then no problems with event bubbling will occur. Putting onclick on input will cause click event to "leak" outside checkbox because this isn't the element that uses actually clicks.

--

Btw, I've made additional tests on ui:inputCheckbox and lightning:input type="checkbox". Unfortunately, in this case - that is you want onclick on parent div that is ignoring child checkbox clicks - you cannot use these components, HTML markup is needed.

Related Topic