7

I am working on simple LWC. I can see that values are changing in the console, but property value is not changing in the component.

I tested the same thing in the Playground too, I see the same issue there also.

HTML:

<template>
    <lightning-card title="Days Left" icon-name="standard:record">
            <div class="slds-m-around_medium">
                    <div style="background: white;padding: 20px;border-radius: 6px;">
                            <div style="font-size: 20px;text-align:center;">{daysFinal}</div>
                            <lightning-button label="Start" onclick={datecounter} style="margin-left: 145px;"></lightning-button>
                    </div>
            </div>
        </lightning-card>
</template>

JS:

import { LightningElement, api, track, wire } from 'lwc';

export default class LoadContact extends LightningElement {

    @track closedt ='2019-08-09';
    @track daysFinal=0;
    @track hoursFinal;
    @track minutesFinal;
    @track secondsFinal;
    timeIntervalInstance;
    totalMilliseconds = 0;

    datecounter() {
        
        let oppCloseDt = new Date(this.closedt);       
        let months = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];                 
        let monthName = months[oppCloseDt.getMonth()];                  
        let dateNumber = oppCloseDt.getDate();                  
        let yearNumber =  oppCloseDt.getFullYear();                 
        let closeDateVar = monthName+' '+dateNumber+' '+yearNumber;                  
        let opptCloseDate = new Date( closeDateVar+" 00:00:00 ");

        // eslint-disable-next-line @lwc/lwc/no-async-operation
        this.timeIntervalInstance = setInterval(function() {
            let opptyCloseDate = new Date(  closeDateVar+" 00:00:00 "); 
            window.console.log('opptyCloseDate...' + opptyCloseDate);                
            let nowdate = new Date();                   
            let timeDiff = opptyCloseDate.getTime()- nowdate.getTime();  
            let seconds=Math.floor(timeDiff/1000); // seconds                   
            let minutes=Math.floor(seconds/60); //minute                    
            let hours=Math.floor(minutes/60); //hours                   
            let days=Math.floor(hours/24); //days                   
             hours %=24;                    
             minutes %=60;                  
             seconds %=60;   
           
             this.hoursFinal =hours;
             this.daysFinal =days;
             this.minutesFinal =minutes;
             this.secondsFinal =seconds;

             window.console.log('this.hoursFinal...' + this.hoursFinal);
             window.console.log('this.daysFinal...' + this.daysFinal);

         
            
        }, 5000);
    }

   
}

Playground: https://developer.salesforce.com/docs/component-library/tools/playground/6dm391HNp/1/edit

enter image description here

2 Answers 2

8

Classic... Javascript is quite weird, this changes quite frequently with respect to the context.

in setInterval , this does not refer to your binded variables, but something else.

You have to pass this as some param in setInterval

import { LightningElement, api, track, wire } from 'lwc';

export default class LoadContact extends LightningElement {

    @track closedt ='2019-08-09';
    @track daysFinal =0;
    @track hoursFinal;
    @track minutesFinal;
    @track secondsFinal;
    timeIntervalInstance;
    totalMilliseconds = 0;


    datecounter(){       

        let oppCloseDt = new Date(this.closedt);       
        let months = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];                 
        let monthName = months[oppCloseDt.getMonth()];                  
        let dateNumber = oppCloseDt.getDate();                  
        let yearNumber =  oppCloseDt.getFullYear();                 
        let closeDateVar = monthName+' '+dateNumber+' '+yearNumber;                  
        let opptCloseDate = new Date( closeDateVar+" 00:00:00 ");
        let myparam = this;

        // eslint-disable-next-line @lwc/lwc/no-async-operation
        setInterval(function() {
            let opptyCloseDate = new Date(  closeDateVar+" 00:00:00 "); 
            window.console.log('opptyCloseDate...' + opptyCloseDate);                
            let nowdate = new Date();                   
            let timeDiff = opptyCloseDate.getTime()- nowdate.getTime();  
            let seconds=Math.floor(timeDiff/1000); // seconds                   
            let minutes=Math.floor(seconds/60); //minute                    
            let hours=Math.floor(minutes/60); //hours                   
            let days=Math.floor(hours/24); //days                   
             hours %=24;                    
             minutes %=60;                  
             seconds %=60;   

             myparam.hoursFinal =hours;
             myparam.daysFinal =days;
             myparam.minutesFinal =minutes;
             myparam.secondsFinal =seconds;
             myparam.daysFinal =null;
             myparam.daysFinal = days;
             window.console.log('this.hoursFinal...' + myparam.hoursFinal);
             window.console.log('this.daysFinal...' + myparam.daysFinal);



        }, 5000 , myparam);
    }


}

Playground Link : https://developer.salesforce.com/docs/component-library/tools/playground/6dm391HNp/2/edit

Src: https://stackoverflow.com/questions/7890685/referencing-this-inside-setinterval-settimeout-within-object-prototype-methods/7890978

JS

1
  • very interesting, not sure how the context changes inside the setInterval. good to know. thank you.
    – Ajay
    Jul 3, 2019 at 19:39
9

This pitfall is quite common for salesforce developers working on Javascript. Set-Interval actually changes the context of this to window as functions like setInterval, setTimeout etc are async functions and hence these functions run after the main thread has finished processing. This can be addressed by any of 2 options:

  1. Lexical Scoping - old fashioned (pls do a google search for understanding)
  2. Arrow functions - Modern javascript. (PFB)

Just change the callback function from:

setInterval(function(){}, 500);

To

setInterval(() => {}, 500);

For simple understanding, Arrow functions don't have their own scope because of which it takes the scope of parent object.

There are many other advantages of arrow functions. Further read: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .