0

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 2

2

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>
2
  • Thanks for the answer, just one question why didn't we use 'this' to access the timer while using clearInterval in the recommended approach?
    – Isha
    Oct 26, 2020 at 17:38
  • @IshaArora That was a mistake. I thought I had put this in all the places. Edited.
    – sfdcfox
    Oct 26, 2020 at 18:14
1

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;
1
  • 3
    let that = this isn't necessary in LWC. Just use an Arrow Function instead; they automatically fix themselves to the object they're defined inside.
    – sfdcfox
    Oct 26, 2020 at 16:27

You must log in to answer this question.

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