TransWikia.com

Arrow function not working for setInterval

Salesforce Asked by Isha on January 20, 2021

I have a countdown in the setInterval function something like this :

     count =5;
     let myparam =this; //Have also tried passing this as some param but doesn't work according to the link below

LWC property is not reactive

 this.Timer = setInterval(() => {
        if(count<=0)
        {
          //refresh the screen
        }
        else
        {
          this.template.querySelector('classname').innerhtml=count;
         }
      count-=1
     },1000)

but the countdown doesn’t decrease on the screen, the same works when I use bind(this), but I don’t want to use it due to the fact that bind(this) creates a copy of function and might cause memory leakage and impact performance. Also, when I use bind(this), the timer takes some time to appear on the same due to interval. Therefore I wanted to separate setInterval and function to be called inside the set interval so that the function can be called before setting the Interval as well and hence counter won’t take some time to display. Probably like

var timer=setInterval(updateTimer,1000);

where updateTimer is a arrow function but its doesn’t work as well.

Any help is appreciated!!

2 Answers

It's not clear that you defined Timer at the class level, this would create an error. Also, members should start with a lowercase character, while classes start with an uppercase character. This is more convention than a rule, but it's a good one to follow.

JavaScript is case-sensitive, so you must use innerHTML, not innerhtml.

Using bind(this) is generally safe and doesn't leak any extra memory, assuming you clear the interval eventually.

You should be using automatic rerendering when possible; direct DOM manipulation is not recommended, but technically acceptable as long as you use lwc:dom="manual".

I wrote up an example using the recommended technique, as well as the not recommended technique you attempted.


import { LightningElement } from "lwc";

export default class Recommended extends LightningElement {
  count = 5;
  timer;
  connectedCallback() {
    this.timer = setInterval(() => {
      if (!this.count) {
        clearInterval(this.timer);
      } else {
        this.count--;
      }
    }, 1000);
  }
  disconnectedCallback() {
    clearInterval(timer);
  }
}

<!-- Recommended approach -->
<template>
    <div>{count}</div>
</template>

import { LightningElement } from "lwc";

export default class NotRecommended extends LightningElement {
  timer;
  connectedCallback() {
    let count = 5;
    this.timer = setInterval(() => {
      if (!count) {
        clearInterval(this.timer);
      } else {
        count--;
        this.template.querySelector("div").innerHTML = count;
      }
    }, 1000);
  }
  disconnectedCallback() {
    clearInterval(this.timer);
  }
}

<!-- Not Recommended approach -->
<template>
    <div lwc:dom="manual"></div>
</template>

Correct answer by sfdcfox on January 20, 2021

I see a couple of things that needs correction in the current code, maybe because it is not the complete code.

  • The count should be this.count.
  • innerhtml is not a valid property of the element. It should be innerHTML.
  • Manipulation of DOM element is something which should usually be done as a last thing, there are several other ways to achieve this using observed properties in LWC. If you still want to manipulate the DOM elements, you should notify the framework by using lwc:dom="manual" attribute.

Sample working example. (Not recomended approach)

import { LightningElement, api } from 'lwc';
export default class TodoApp extends LightningElement {
  count = 10;
  myTimer(){
    let that = this;
    return setInterval(function() {
        if(that.count<=0){
          // DO something
        }
        else{ 
          that.template.querySelector('.timer').innerHTML= that.count;
        }
      that.count-=1
     },1000, that)
  }
  connectedCallback(){
    this.myTimer();
  }
}

HTML

<template>
  <div lwc:dom="manual" class='timer'>TIMER</div>
</template>

Recommended way

Use a property to show the count and manipulate it instead

  • Declare a property named timer timer = 0;
  • In the JS file instead of using queryselector to manipulate DOM, manipulate the JS property. that.timer = that.count;

Answered by manjit5190 on January 20, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP