Reputation: 396
Hi I'm making a pomodoro clock. I want to allow the timer to increase or decrease every 100 milliseconds when the user holds down the button. The running conditions for mousedown and clickUpdate are very similar.
The entire code of clickUpdate relies on using this keyword to achieve that goal. But how can I let setInterval inherit or have access to this keyword? This referring to the button object that mousedown is a method of.
https://codepen.io/jenlky/pen/ypQjPa?editors=0010
var timer;
const session = document.getElementById("session");
const breaktime = document.getElementById("break");
const mins = document.getElementById("mins");
const secs = document.getElementById("secs");
function clickUpdate () {
// if data-action = increase and its under session-input, increase session.value else increase breaktime.value
if (this.dataset.action === "increase") {
if (this.parentElement.className === "session-input") {
// if session.value is 60 mins, this increase click changes it to 1 min
if (session.value === "60") {
session.value = 1;
} else {
session.value = Number(session.value) + 1;
}
mins.innerText = session.value;
// if breaktime.value is 60 mins, this increase click changes it to 1 min
} else {
if (breaktime.value === "60") {
breaktime.value = 1;
} else {
breaktime.value = Number(breaktime.value) + 1;
}
}
}
// if data-action = decrease and its under session-input, decrease session.value else decrease breaktime.value
if (this.dataset.action === "decrease") {
if (this.parentElement.className === "session-input") {
// if session.value is 1 min, this decrease click changes it to 60 mins
if (session.value === "1") {
session.value = 60;
} else {
session.value = Number(session.value) - 1;
}
mins.innerText = session.value;
// if breaktime.value is 1 min, this decrease click changes it to 60 mins
} else {
if (breaktime.value === "1") {
breaktime.value = 60;
} else {
breaktime.value = Number(breaktime.value) - 1;
}
}
}
console.log(this);
}
// Problem is how can I let clickUpdate or setInterval(function(){},100) inherit this
// setInterval's function doesn't seem to inherit or have any parameters
// I'm not sure how forEach thisArg parameter works, or how to use bind, or how to use addEventListener last parameter
function mousedown() {
var obj = this;
timer = setInterval(clickUpdate, 100);
}
function mouseup() {
if (timer) {
clearInterval(timer);
}
}
const buttons = Array.from(document.getElementsByClassName("symbol"));
mins.innerText = session.value;
//buttons.forEach(button => button.addEventListener("click", clickUpdate));
buttons.forEach(button => button.addEventListener("mousedown", mousedown));
buttons.forEach(button => button.addEventListener("mouseup", mouseup));
console.log(session);
Upvotes: 1
Views: 76
Reputation: 101690
The this
value within functions defined using function () ...
is usually dependent on how the function is called. If you call a.myFunction()
then this
within the function will be a reference to a
. If you call myFunction()
, then this
will either be undefined
or the global object depending on whether you are using strict or sloppy mode.
Usually the most straightforward way to get a callback function to use a particular this
value is to use .bind(n)
. This basically creates a wrapped version of the original function, with the this
value locked in as n
setInterval(clickUpdate.bind(this), 100);
Then again, my preference would be to not use this
at all. It's confusing and has wacky behavior that often requires all sorts of contrived workarounds (as you have experienced). You could just as easily pass in the value as a parameter here:
function mousedown(e) {
timer = setInterval(clickUpdate, 100, e.target);
}
Upvotes: 2
Reputation: 9
One trick is to create a separate reference (either global or at least on a common ancestor scope) holding the reference to the "this" reference from the level you want.
Once you do that, you can refer to it within the setInterval function.
Example:
var scope = this;
this.name = 'test';
setInterval(function() {
console.log(scope.name); // should print 'test' every 1 second
},1000);
Upvotes: 0