Reputation: 37
I'm creating a custom 'Counter' component with HTMLElement
Here is the HTML for this component:
<template id="counter-template">
<div class='counter__wrapper'>
<h2 id='counter__status'></h2>
<button id='continue'>Continue</button>
<button id='stop'>Stop</button>
</div>
</template>
<script src="Counter.js"></script>
and the Counter.js code:
const currentDocument = document.currentScript.ownerDocument;
class CustomCounter extends HTMLElement {
constructor() {
super();
this.count = 0;
this.enableCount = true;
}
static get observedAttributes() {
return ["count"];
}
attributeChangedCallback(name, oldValue, newValue) {
if (this.enableCount) {
this.count = newValue;
this.shadowRoot.querySelector('#counter__status').innerHTML = this.count;
}
}
connectedCallback() {
const shadowRoot = this.attachShadow({mode: 'open'});
const template = currentDocument.querySelector('#counter-template');
const instance = template.content.cloneNode(true);
shadowRoot.appendChild(instance);
this.setAttribute('count', this.count);
this.shadowRoot.querySelector('#stop').addEventListener('click', function() {
this.enableCount = false;
})
}
}
customElements.define('custom-counter', CustomCounter);
The component is working fine, but I'm using it in a setInterval function, where I am setting the 'count' attribute to the interval's iterator, like this:
var counter = document.querySelector('custom-counter');
var i = 1;
var completedAt = 10;
var interval = setInterval(() => {
counter.setAttribute('count', i);
if (i == completedAt) {
clearInterval(interval);
}
i++;
}, 1000);
and it's working fine, the 'count' attribute is changing and being displayed in the html.
Now, the problem is that I need to stop the counter when I click the 'stop' button, and as you can see I've added a click listener in the connectedCallback() that will set the value of this.enableCount to false,
and despite having an if statement to check this.enableCount before updating the html in attributeChangedCallback()
attributeChangedCallback(name, oldValue, newValue) {
if (this.enableCount) { // <==== THIS ONE
this.count = newValue;
this.shadowRoot.querySelector('#counter__status').innerHTML = this.count;
}
}
The count does not stop when I click the stop button. (If I console.log the value of this.enableCount it's giving me false, but the count does not stop updating)
Upvotes: 0
Views: 58
Reputation: 56753
You have a this
problem.
Inside your anonymous click handler function
this.shadowRoot.querySelector('#stop').addEventListener('click', function() {
this.enableCount = false;
})
this
is not your webcomponent, but the button being clicked. You can fix that in three ways:
a) Use an arrow function which does not have a this
of its own:
this.shadowRoot.querySelector('#stop').addEventListener('click', () => {
this.enableCount = false;
})
b) Explicitly state what this
inside your handler function should be by using Function.prototype.bind()
:
this.shadowRoot.querySelector('#stop').addEventListener('click', function() {
this.enableCount = false;
}.bind(this))
c) Use a closure and define a correctly scoped variable holding a reference to this
:
const self = this;
this.shadowRoot.querySelector('#stop').addEventListener('click', function() {
self.enableCount = false;
})
Upvotes: 1