[SalesForce] AfterRender on button in Lightning Component (DOM update)

I am trying to do something that sounds easy in JavaScript but that I have difficulty to do with Lightning component.

The functionality is to highlight the currently pressed button as explained in this link.

I have created a div in my component as below :

<div id="myDIV">
  <lightning:button class="btn" aura:id="bout" label="1"/>
  <lightning:button class="btn active" aura:id="bout" label="2"/>
  <lightning:button class="btn" aura:id="bout" label="3"/>
  <lightning:button class="btn" aura:id="bout" label="4"/>
</div>

And the related css:

/* Style the buttons */
.THIS .btn {
  border: none;
  outline: none;
  padding: 10px 16px;
  background-color: #f1f1f1;
  cursor: pointer;
}

/* Style the active class (and buttons on mouse-over) */
.THIS .active{
  background-color: #666;
  color: white;
}

.THIS .btn:hover{
  background-color: #666;
  color: white;
}

And then try to add the listener to my helper :

addListeners: function (component){
        var header = document.getElementById("myDIV");
        var btns = header.getElementsByClassName("btn");
        for (var i = 0; i < btns.length; i++) {
            btns[i].addEventListener("click", function() {
                var current = document.getElementsByClassName("active");
                current[0].className = current[0].className.replace(" active", "");
                this.className += " active";
            });
        };
    }

And to finish create my render:

afterRender: function (component, helper) {
    var afterRend = this.superAfterRender();
    helper.addListeners(component)
    return afterRend;
}

The result look like this:
enter image description here

However, when I click on another number, it doesn't update the DOM to define the clicked one as active.

Anyone to guide on how to succeed this?

Best Answer

I would not use afterRender to attach events, as you'll end up possibly adding duplicate events. Here's a simplified version that does not rely on a renderer:

<aura:application >
    <div id="myDIV" onclick="{!c.setActive}">
        <lightning:button class="btn" aura:id="bout" label="1"/>
        <lightning:button class="btn active" aura:id="bout" label="2"/>
        <lightning:button class="btn" aura:id="bout" label="3"/>
        <lightning:button class="btn" aura:id="bout" label="4"/>
    </div>
</aura:application>

({
    setActive: function(component, event, helper) {
        var bout = component.find("bout");
        bout.forEach(function(v) {
            $A.util.removeClass(v, "active");
        });
        $A.util.addClass(event.target, "active");
    }
})

Of course, in a real application, you'd probably put this method in a helper, but for demonstration purposes, the logic is instead in the controller.

Related Topic