[SalesForce] afterRender() method is not modifying the DOM after the Lightning component’s load

According to Salesforce documentation,

The afterRender() method is called to enable you to interact with the
DOM tree after the framework’s rendering service has inserted DOM
elements

I have a Lightning component and I want to add some class to an element after the component has completed its load. But this doesn't work, the class doesn't get added to the element. Here is my code.

({
    afterRender: function(cmp, helper) {
        this.superAfterRender();
        var lst_officeElements = document.getElementsByClassName('myMenuItem');
        lst_officeElements[0].className += " slds-active";
    }
})

When I use a timer though, with JavaScript function window.setTimeout() with 2 seconds delay, it works.

Can anyone help me with this? Is my understanding of the afterRender() method correct? I'm expecting this method to do stuff on the DOM ounce my component has completely loaded its content (DOM), kind of an equivalent of the jQuery function .ready().

Here is my Markup:

<aura:component controller="OfficeCtrl" implements="flexipage:availableForAllPageTypes" access="global"> 
    <aura:handler name="init" action="{!c.doInit}" value="{!this}" />
    <aura:registerEvent name="OfficeEvent" type="c:OfficeEvent" />
    <aura:attribute name="offices" type="Office__c[]" />
    <aura:attribute name="officesMap" type="Map" />
    <div class="slds-tabs--default">
        <ul class="slds-tabs--default__nav" role="tablist">
            <aura:iteration items="{!v.offices}" var="myOffice">
                <li class="myMenuItem slds-tabs--default__item slds-text-title--caps" title="{!myOffice.Name}" role="presentation" id="{!myOffice.Id}" onclick="{!c.selectOffice}">
                    <a class="slds-tabs--default__link" role="tab" aria-selected="false">
                        {!myOffice.Name}
                    </a>
                </li>
            </aura:iteration>
        </ul>
    </div>
</aura:component>

Here is the rest of the code of my component (it is not really related to the problem I'm facing though). Here is the controller:

({
    doInit : function(cmp, event, helper) {
        let getOfficesAction = cmp.get("c.getOffices");
        getOfficesAction.setCallback(this, function(response) {
            let state = response.getState();
            if (cmp.isValid() && state === "SUCCESS") {
                let lst_offices = response.getReturnValue();
                if (lst_offices.length == 0) {
                    return;
                }

                let map_offices = {};
                let size = lst_offices.length;
                for (let i = 0; i < size; i++) {
                    map_offices[lst_offices[i].Id] = lst_offices[i];
                }

                cmp.set("v.offices", lst_offices); 
                cmp.set("v.officesMap", map_offices); 

                let officeEvent = $A.get("e.c:OfficeEvent");
                officeEvent.setParams({"office": lst_offices[0]});
                officeEvent.fire();
            }
            else {
                console.log("Failed with state: " + state);
            }
        });
        $A.enqueueAction(getOfficesAction);
    },

    selectOffice: function(cmp, event, helper) {
        let map_offices = cmp.get("v.officesMap");
        let lst_offices = cmp.get("v.offices");
        let currentOfficeId = event.currentTarget.getAttribute("id");
        helper.selectOfficeHlp(lst_offices, map_offices, currentOfficeId);
    }
})

And here is the helper:

({
    selectOfficeHlp: function(p_offices, p_officesMap, p_currentOfficeId) {
        if (p_offices.length == 0) {
            return;
        }

        p_offices.map(function(myOffice) {
            document.getElementById(myOffice.Id).className = "myMenuItem slds-tabs--default__item slds-text-title--caps";
        });

        $A.util.addClass(document.getElementById(p_currentOfficeId), 'slds-active');
        this.fireOfficeEvent(p_officesMap[p_currentOfficeId]);
    },

    fireOfficeEvent: function(p_office) {
        let officeEvent = $A.get("e.c:OfficeEvent");
        officeEvent.setParams({"office": p_office});
        officeEvent.fire();
    }
})

Thanks a lot

Best Answer

Second try here...

For adding class Names I'd suggest you use $A.util.addClass(), the component has a chance to rerender a lot and it will clobber your changes if you don't set it on the component as well

$A.util.addClass(cmp, "slds-active");

You could also try using getElement() on the component

var element = cmp.getElement().classList.add("slds-active");
Related Topic