stacki
stacki

Reputation: 23

Setinterval in JS customelement

I am working on a HTML customelement, but when I run it in the browser, I get a very interesting error. This is the code:

class clock extends HTMLElement {
        constructor() {
            super()
            this.time = new Date(this.getAttribute('time'));
            this.span = document.createElement('span')
            this.appendChild(this.span)
        }

        Timer() {
            let Now = this.time;           
            let Seconds = Now.getSeconds();
            let Minutes = Now.getMinutes();
            let Hours = Now.getHours();  

            Minutes = Minutes < 10 ? "0" + Minutes : Minutes;

            document.getElementById("digitalClock").textContent =  Hours + ":" + Minutes; 
        }

        connectedCallback(){
            this.span.innerHTML = `...<span id="digitalClock"></span>`;
            this.Timer();
            this.myClockTimer = setInterval(this.Timer, 5000);
        }
        disconnectedCallback(){
            clearInterval(this.myClockTimer);
        }

    }
customElements.define('worktime-clock', clock)

When I run this, the Timer function runs well when calling with this.Timer() in the connectedCallback function, but one line after, when it gets into a cycle, it says that Now is undefined in Timer function. It seems like there is a problem about calling it in setinterval, however, the function is definitely running again and again as expected. Does someone know what is the problem?

Upvotes: 0

Views: 533

Answers (2)

Or an arrow function

<script>
  customElements.define('worktime-clock', class extends HTMLElement {
    updateTime() {
      let Now = new Date();
      const pad = x => String(x).padStart(2,'0');
      const H = pad(Now.getHours());
      const M = pad(Now.getMinutes());
      const S = pad(Now.getSeconds());
      this.innerHTML = `${H}:${M}:${S}`;
    }
    connectedCallback() {
      this.myClockTimer = setInterval(() => {
        this.updateTime();
      }, 1e3);
    }
  })

</script>
<worktime-clock>21:22:23</worktime-clock>

Or for a code-golf competition

<script>
  customElements.define('worktime-clock', class extends HTMLElement {
    connectedCallback() {
      setInterval(() => {
        this.innerHTML = new Date().toString().split` `[4];
      }, 1e3);
    }
  })

</script>
<worktime-clock>21:22:23</worktime-clock>

Upvotes: 1

Đinh Carabus
Đinh Carabus

Reputation: 3494

You lose the correct this context by passing the Timer function as a callback. As a result this (within the callback) now points to window instead. You can use bind to set the this-context:

this.myClockTimer = setInterval(this.Timer.bind(this), 5000);

This accomplishes the same thing:

var that = this;
this.myClockTimer = setInterval(function() { that.Timer(); }, 5000);

Another alternative:

this.myClockTimer = setInterval(function() { this.Timer(); }.bind(this), 5000);

Upvotes: 2

Related Questions