2

I have a lightning component which set a div's background color to red in the doInit method using jquery,is added as an lightning tab.

When i visit the tab in lightning experience for the first time, the component is loaded,div's bg color is properly set to red.But when i navigate to few tabs and come back to the above tab.

doInit is fired but the jquery is not setting the backgroud color of the div.

While debugging i found out the selector $('#TestDiv') (i.e jquery element object) logged in dev console is different for subsequent loads when compared with the first log,which seems odd.

I suspect this is because of the second or more the time the tab is visited, component definition from the cache is loaded,which inturn alters dom structure i suppose(i may be wrong)so that jquery fails to retrieve the proper dom element(which it did the first time the component was loaded).

Here's my code:

TestCmp.cmp

<aura:component implements="force:appHostable" access="public">
    <ltng:require scripts="/resource/FullCalendar/FullCalendar/jquery-1.8.2.min.js"  />
    <aura:handler name="init" action="{!c.doInit}" value="{!this}" />

    <div id="testDiv" style="height:100px;">
        test div txt
    </div>
</aura:component>

TestCmpController.js

({
    doInit:function(cmp,evt,helper){
        console.log('setting bg:::')
        $('#testDiv').css('background-color', 'red');
        console.log('done setting bg:::')
    }
})

-- UPDATE --

As @ratan mentioned ,i am aware of the lightning component's api method to modify the styles. I tried to debug the cause of the issue mentioned here while doing so i found a issue in retrieving the dom element using jquery on subsequent loads ,so i built an above component to explain the issue.

  • If you want to manipulate the css dynamic you can do it without jquery as well check this example developer.salesforce.com/docs/atlas.en-us.lightning.meta/… – Ratan Paul May 13 '16 at 7:28
  • @Ratan i know it can be done in lightning component api methods.I tried to debug the cause of the issue mentioned here while doing so i found a issue in retrieving the dom element using jquery on subsequent loads ,so i built an simple component to explain the issue. – Praveen May 13 '16 at 7:34
4

There are a few issues in your example:

  • init is not synchronized in any way with dynamic loading of javascript or rendering which is why <ltng:require afterScriptsLoaded="{!c.yourAfterScriptLoadedHandler}"> exists (it handles both of those challenges by sequencing one or more script onload events and the rendering lifecycle of lightning).

  • init handlers are called long before rendering happens which means that there is a timing issue there too.

  • S1/LEX has built in tab content caching (I believe it hold on to the last 5 tabs' content) and init is only called once in a component's lifecycle (right after creation)

  • manipulating DOM elements that are created on your behalf by the framework puts you at odds with the auto rerendering process and direct CSS modifications are likely to be unceremoniously overwritten. If you really need to do this it should be done in afterRender()

  • Doug,Thanks for answering.I tried doing the background color setting process in afterScriptsLoaded it works in a standalone app but works only the first time the component is loaded in lightning experience not on subsequent loads. – Praveen May 13 '16 at 15:51
  • I tried same in afterRender too but i got $ is not defined since the jquery was not loaded yet.So how can i make sure the jquery is available when i perform DOM manipulation in the afterRender?. I think timeout might help but i believe it not a good solution. – Praveen May 13 '16 at 15:54
0

I totally agree with Doug's view,but i don't think there's way in lightning component to make sure the 3rd party libraries like Jquery,FullCalendar... are available before doing DOM manipulation in afterRender.

window.setTimeout might be a solution but still i don't thing its good idea.

As a workaround to do DOM manipulation using 3rd party libraries for now,we need to use afterScriptsLoaded method only(which makes sures the libraries are available).

Moving on to the answer,the recommended way to get the DOM in LC is by using component.find().getElement()' instead of using jquery selector.Because the former returns the actual DOM properly irrepective of the loads in LEX,SF1,Standalone App.

Here's the code:

TestCmp.cmp

<aura:component implements="force:appHostable" access="public">
    <ltng:require scripts="/resource/FullCalendar/FullCalendar/jquery-1.8.2.min.js"  afterScriptsLoaded="{!c.doInit}" />

    <div aura:id="testDiv" style="height:100px;">
        test div txt
    </div>
</aura:component>

TestCmpController.js

({
    doInit:function(cmp,evt,helper){
        console.log('setting bg:::')
        var ele = component.find('testDiv').getElement();
        $(ele).css('background-color', 'red');
        console.log('done setting bg:::')
    }
})

I still think the above solution is an workaround,because the LC documentation and also Doug's recommendation is to do the DOM manipulation only in afterRender.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.