7

I used setTimeout() of javascript, and my code to be executed is also is getting executed, but somehow the $A.util.removeClass and $A.util.addClass are not working and my component(i.e a Toast written in slds markup) to be hidden is not getting hidden. Is there any known workaround?

Controller method:

addDelay : function(component, event, helper){
    var delay=4000; //4 seconds
    setTimeout(function() {
        console.log('Inside delay: ');
        var toastDiv= component.find('toastDiv');
        console.log('toastDiv:  '+ toastDiv);
        $A.util.removeClass(toastDiv, "slds-show");
        $A.util.addClass(toastDiv, "slds-hide");
    }, delay);

Here, toastDiv is the ID of div element of Toast component markup.

Output of console: SecureComponent: markup://aura:html {289:0} {toastDiv}{ key: {"namespace":"c"}

which means it is fetching the div correctly.

UPDATED CODE FOR REFERENCE:

        window.setTimeout(
        $A.getCallback(function() {
            if(component.isValid()){
                var toastDiv= component.find('toastDiv');
                $A.util.removeClass(toastDiv, "slds-show");
                $A.util.addClass(toastDiv, "slds-hide");
            }
            else{
                console.log('Component is Invalid');
            }
        }), 3000
    );
8

setTimeout() as a "fix" for timing issues is rarely a good choice - just moves the indeterminacy to another place /or adds lag (4 seconds is an eternity). The correct way to handle this is with either data binding to myDiv's v.class attribute (best) or in a custom renderer.

Setting that aside it's also critical to note that myDiv is actually a component and not an element (Component.find() always works st the component api level). The remove/addClass() util methods are also operating at the component level (they manipulate the v.class attribute). Why does this matter? By introducing a callback using setTimeout() you have also introduced code execution outside of Lightning's visibility and any time this is fine you need to wrap your callback with a call to $A.getCallback() to allow Lightning to restore context and also run its event/render lifecycle. Without $A.getCallback() Lightning does not know to even look to see that you have change myDiv.v.class and therefor does not update the corresponding DOM element's classList.

See Modifying Components Outside the Framework Lifecycle https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/js_cb_mod_ext_js.htm for more info - but like I said please reconsider your approach entirely and switch to a simpler declarative (value binding to an attribute on your component that contains myDiv) approach and let Lightning handle the timing etc.

  • Thanks Doug! I alost forgot about the getCallback() method...yes you are right it is out of lightning context. Also agree with your advise not to use etTimeout(). But at the same time , I am not able to fathom how can I make my toast stay on UI for some time and then go away...if I use data binding in myDiv as you said, it just disappears even before we can see. Can you please guide in detail how can I achieve this? – Sarang Nov 23 '16 at 12:38
  • Sorry - I missed the important detail about this being a toast/timed prompt - that is one of the few legitimate uses of setTimeout() :-) – Doug Chasman Nov 23 '16 at 14:36
  • I'm a definite newbie at all things HTML and CSS, but could CSS transitions be used to fade something out after a certain number of seconds? I thought I remember reading that a transition also didn't have to be linear, and that it could have a defined ramp to it. Maybe the first 3.9 seconds could be fully visible, and then it transitions/fades out for the last .1 second? – Florissant53 Nov 24 '16 at 1:44

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.