I have this simple code:
var Modules = (function() {
'use strict';
return {
TIMER: function (){
var timer = null;
return {
time: 100,
init: function() {
this.counter();
this.timer = window.setInterval(this.counter, 1000);
},
counter: function() {
this.time -= 1;
if (this.time <= 0) {
window.clearInterval(this.timer);
alert('Time expired');
}
console.log(this.time);
this.viewer();
},
viewer: function() {
document.getElementById('timer').innerHTML = this.time;
}
}
}
};
}());
Modules.TIMER().init();
<div id="timer"></div>
And something is wrong because I got 2 errors:
this.viewer is not a function
and
NaN of this.time
What it wrong with my design pattern running over interval?
After extend TIMER to reset method:
reset: function() {
this.time = 100;
}
and call it outside as:
Modules.TIMER().reset();
?
I got
this.time is not defined
.
Or inside init:
jQuery("body").on('keyup mouseup', function (e) {
this.reset();
});
I got error:
this.reset() is not s function.
Your issue is coming from this line:
this.timer = window.setInterval(this.counter, 1000);
When you are invoking the callback in the setInterval
method, the this
in the callback function no longer refers to your TIMER
object, but the window
.
.bind(this)
to bind lexical this
to callbackYou will need to bind the current context to the callback:
this.timer = window.setInterval(this.counter.bind(this), 1000);
var Modules = (function() {
'use strict';
return {
TIMER: function (){
var timer = null;
return {
time: 100,
init: function() {
this.counter();
this.timer = window.setInterval(this.counter.bind(this), 1000);
},
counter: function() {
this.time -= 1;
if (this.time <= 0) {
window.clearInterval(this.timer);
alert('Time expired');
}
console.log(this.time);
this.viewer();
},
viewer: function() {
document.getElementById('timer').innerHTML = this.time;
}
}
}
};
}());
Modules.TIMER().init();
<div id="timer"></div>
setInterval
callbackNote: Personally, I prefer this solution because it uses ES6, but if you are still supporting legacy browsers and do not want to transpile your JS, this might not be the best solution.
Another alternative will be using an arrow function in the callback of setInterval
, instead of assigning the this.counter
function as the callback directly:
this.timer = window.setInterval(() => this.counter(), 1000);
The arrow function preserves the lexical this
, so when this.counter()
is invoked it will be using the same context, i.e. the internal this
will be referencing your TIMER
object.
var Modules = (function() {
'use strict';
return {
TIMER: function (){
var timer = null;
return {
time: 100,
init: function() {
this.counter();
this.timer = window.setInterval(() => this.counter(), 1000);
},
counter: function() {
this.time -= 1;
if (this.time <= 0) {
window.clearInterval(this.timer);
alert('Time expired');
}
console.log(this.time);
this.viewer();
},
viewer: function() {
document.getElementById('timer').innerHTML = this.time;
}
}
}
};
}());
Modules.TIMER().init();
<div id="timer"></div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With