javascript: the "this" issue in setInterval (again) [duplicate] - javascript

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
JavaScript setInterval and `this` solution
(9 answers)
Closed 8 years ago.
EDIT: The practice below is NOT correct. The solution is to store "this" in another variable and use that in the setInterval function. See answers below.
this.growImage = function() {
console.log("growImage:" + this.dom.id + "counter:" + this.grow_counter);
if(this.grow_counter == 0) {
this.tim_grow = window.setInterval(
/******* FUNCTION TO BE CALLED BY SETINTERVAL ********/
function() {
this.grow_counter++;
console.log("this.growStepByStep(): this.grow_counter = " + this.grow_counter); /*this is displayed as NaN */
if(this.grow_counter > this.times) {
window.clearInterval(this.tim_grow);
this.grow_counter = 0;
}
}
/******* FUNCTION TO BE CALLED BY SETINTERVAL ********/
,
20);
}
}
EDIT: The above solution is NOT correct.
It does not work. The console log does not "see" this.grow_counter, and displays a NaN instead. this.grow_counter is just a numeric value.
NOTE: that this function uses this inside it, so other simpler solutions won't do either.
Thanks in advance!

The value of this is NOT preserved in your setInterval() callback. You have to save that value you want to another variable before the setInterval() call and use that inside the setInterval().
this.growImage = function() {
console.log("growImage:" + this.dom.id + "counter:" + this.grow_counter);
if(this.grow_counter == 0) {
var self = this;
this.tim_grow = window.setInterval(
/******* FUNCTION TO BE CALLED BY SETINTERVAL ********/
function() {
self.grow_counter++;
console.log("self.growStepByStep(): self.grow_counter = " + this.grow_counter); /*this is displayed as NaN */
if(self.grow_counter > this.times) {
window.clearInterval(self.tim_grow);
self.grow_counter = 0;
}
}
/******* FUNCTION TO BE CALLED BY SETINTERVAL ********/
,
20);
}
}
Or, if you are using modern browsers only, you can also use .bind() to manipulate the value of this to be set as you want like this:
this.growImage = function() {
function intervalCallback() {
this.grow_counter++;
console.log("this.growStepByStep(): this.grow_counter = " + this.grow_counter); /*this is displayed as NaN */
if(this.grow_counter > this.times) {
window.clearInterval(this.tim_grow);
this.grow_counter = 0;
}
}
console.log("growImage:" + this.dom.id + "counter:" + this.grow_counter);
if(this.grow_counter == 0) {
this.tim_grow = window.setInterval(intervalCallback.bind(this), 20);
}
}

Neit is correct, but to give a little bit more info.
You aren't understanding the scope that you are in when inside the setInterval.
Inside of your setInterval, you've created a new scope and 'this' only refers to things inside that new scope. His/her suggestion of setting a variable me = this and then using me.grow_counter means you are storing the outer scope in the variable 'me', which can then be used in your setInterval scope (although I would like to see a better variable name!).
Hope that helps.

Related

setInterval returns undefined OR scope of returned value wrong [duplicate]

This question already has answers here:
JavaScript setInterval and `this` solution
(9 answers)
How to access the correct `this` inside a callback
(13 answers)
Closed 5 months ago.
I try to store Date.now() after a setIntervall invoked a callback. After that, I'd like to clear the intervall, so it only fires once. All that in a class.
But the variable I store the intervalID in and I hoped would be available "class-wide" keeps "undefined". I am pretty sure I am doing sth awfully wrong with JS scope, but I cannot find out what.
class Signal {
t : number;
private intervallId : number | undefined;
constructor(t : number) {
this.t = t;
}
wait() {
this.intervallId = setInterval(this.signalTriggered, this.t)
console.log("Never executed.")
}
signalTriggered() {
const triggerTime : number = Date.now()
console.log(this.intervallId) /* always undefined */
if (this.intervallId) {clearInterval(this.intervallId)
console.log(triggerTime); }
}
}
var timer = new Signal(2000)
timer.wait()
console.log("Done.") /* Never printed out. */
The problem is the reference of the this, you are losing the original reference of it when passing the method as an argument to setIterval.
You could use an arrow function to wrap the method:
setInterval(() => this.signalTriggered(), this.t)
Or use Function.prototype.bind to assign the reference of this:
setInterval(this.signalTriggered.bind(this), this.t)

Javascript this context binding [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
How does the "this" keyword work, and when should it be used?
(22 answers)
Closed 4 years ago.
I am trying to understand the bind method and I have written the below code :
//
//Window Context
function Hello(d) {
//Always this reffers to calling context
console.log(d);
}
Hello("ABC");
function Student(sname) {
this.name_n = sname;
this.hello = Hello;
this.printAfter2Seconds = printAfter2Seconds.bind(this);
this.print = function() {
console.log(`Student Name: ${this.name_n}`);
}
}
printAfter2Seconds = function() {
console.log(`Before Set TimeOut - ${this.name_n}`);
//let that = this;
setTimeout(function() {
//console.log(this);
console.log(`After Set TimeOut - ${this.name_n}`);
},2000);
}
function Department(dname) {
this.name_n = dname;
this.hello = Hello;
this.printAfter2Seconds = printAfter2Seconds.bind(this);
}
let s = new Student("ABC");
s.hello(s.name_n);
s.printAfter2Seconds();
let d = new Department("IT");
d.hello(d.name);
d.printAfter2Seconds();
//
If I comment the setTimeout line and the line ending setTimeout like below :
//setTimeout(function() {
//console.log(this);
console.log(`After Set TimeOut - ${this.name_n}`);
// },2000);
I am getting the expected output ABC and IT. But If I include setTimeout I am getting undefined both time. So I am guessing some where I need to invoke bind again. This may not be a trivial example that you use everyday just trying to understand bind.
So I need to understand how to bind the this context of the function inside setTimeout or that is even possible.
Thanks in Advance.

Javascript this keyword return undefined [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 7 years ago.
i'm trying build slideshow function with OOP literal way.
so, this is my code :
"use strict";
var slideshow = {
elSet : $(".slideshow"),
elCount : indexCount(".dealList"),
elWidth : width(".dealList"),
elNo : 1,
next : function() {
if (this.elNo < this.elCount) {
console.log(this.elSet);
this.elNo += 1;
this.elSet.style.transform = "translateX(-" + this.elWidth * this.elNo + "px)";
}
else {
console.log(this.elSet);
this.elNo = 1;
this.elSet.style.transform = "translateX(-" + this.elWidth * this.elNo + "px)";
}
},
initial : function() {
var loop = setInterval(this.next, 5000);
}
}
slideshow.initial();
the problem occure in browser console :
out of memory
console.log return undefined
it is possible the problem occure because of this keyword?
what's wrong with my code?
The callback of the setInterval() when executed is bound to the global object and not your object. You can, however, bind it to your object by using this code instead:
initial : function() {
var loop = setInterval(this.next.bind( this ), 5000);
}
MDN on bind()

passing an html id into javascript function

I am learning JavaScript and I do not understand how to pass an ID from html into a JavaScript function.
My CSS page has this here:
#quizclock (with properties here)
And on my HTML page I have a javascript function as so:
<script type="text/javascript">
var seconds = 0;
var clockId;
function runClock()
{
seconds + 1;
quizclock = seconds; //right here is my problem.
}
function startClock()
{
showQuiz();
runClock();
setInterval("runClock()", 1000);
}
function stopClock()
{
clearInterval(runClock);
gradeQuiz();
return = correctAns;
alert("You have " + correctAns + " correct out of 5 in " + quizclock + " seconds.");
}
</script>
So I need to use the id quizclock in the function. Any tips?
I noticed a few other problems with your code, I've commented the fixes and added a couple of other tips too.
var seconds = 0;
var clockId;
var correctAns;
// Lets get a reference to the quizclock element and save it in
// a variable named quizclock
var quizclock = document.getElementById('quizclock');
function runClock() {
// seconds + 1;
// This calculates seconds + 1 and then throws it away,
// you need to save it back in to the variable
// You could do that with:
// seconds = seconds + 1;
// But it would be even better with the shorthand:
seconds += 1;
// set the HTML inside of the quizclock element to new time
quizclock.innerHTML = seconds;
}
function startClock() {
showQuiz();
runClock();
// setInterval("runClock()", 1000);
// When using setInterval and setTimeout you generally just
// want to directly pass it the function by name. Passing it
// a string "runClock()" is in effect actually running
// eval("runClock()"), eval should be avoided unless you
// really need it.
// setInterval returns a number which identifies the interval,
// you need to save that number, you'll need it when you
// call clearInterval
clockId = setInterval(runClock, 1000);
}
function stopClock() {
// clearInterval takes the id that setInterval
// returned to clear the interval
clearInterval(clockId);
gradeQuiz();
// you had this alert statment after the return statement,
// it would have never run, return statements end the
// function and anything after them is ignored
alert("You have " + correctAns + " correct out of 5 in " +
quizclock + " seconds.");
//return = correctAns;
// the return statement doesn't need a =,
// return = correctAns says set a variable named return to the
// value of correctAns since return is a reserved word,
// that should generate an error
return correctAns;
}
Some useful reference links:
setInterval
clearInterval
getElementById
Reserved Words (Things that can't be used as variable names)
Assignment Operators (More shortcut operators listed here)
Introducing the JavaScript DOM
An Inconvenient API: The Theory of the Dom
If this is for a formal class you might have to just use basic DOM methods to get elements (getElementById, etc). If you are just learning on your own I would encourage you to learn a DOM library. I would suggest jQuery, it is easy to learn and is now more or less the de facto standard. With jQuery instead of document.getElementById('quizclock') you could just do this: $('#quizclock'). Using jQuery makes your code a little shorter, standardizes things between different browsers and helps protect you from bugs in those browsers.
You are just a beginner now, in small examples like this you don't need to worry about global variables, but you should know that it is generally a bad idea to use too many of them. What if another function on the page also used a global variable named seconds? It might change seconds and screw up your timer. This is getting a little advance, but one way to avoid this is to wrap your code in a self-invoking anonymous function:
(function () {
var seconds = 0;
// inside here seconds is visible and can be used
}());
// outside seconds is not declared, it will return undefined.
Unfortunately any functions inside will also not be visible on the outside, so attaching them via onclick= wouldn't work but you could (should) attach them in using the DOM:
var submitButton = document.getElementById('submitanswers'); // you'll have to give the button an id
submitButton.addEventListener('click', stopClock, false);
Again, using jQuery would make this even easier:
$('#submitanswers').on('click', stopClock);
Likewise if you use jQuery, it already forces you to wrap your code in a function which will keep your variables out of the globalnamespace:
$(document).ready(function () {
var seconds;
// again seconds is visible here
});
// but not here
You can select an element with:
var quizclock = document.getElementById('quizclock');
You can then set the value with:
quizclock.innerHTML = seconds;

How can I attach a change event handler to a variable? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Listening for variable changes in JavaScript or jQuery
How can I track if this variable has changed?
var ConditionalFlag = 0;
I tried this:
var ConditionalFlag = 0;
$(ConditionalFlag).change(function () {
alert("Changed");
});
ConditionalFlag++;
But to no avail. I have considered using a 25ms timer to check for change like this:
var ConditionalFlag = 0;
function CheckFlag() {
if (ConditionalFlag > 0) {
alert("Changed");
clearInterval(check);
}
}
var check = window.setInterval("CheckFlag()", 25);
ConditionalFlag++;
However, that seems like overkill. Is there a way to attach an event handler to this variable with jQuery or javascript?
If it's a global variable, you can use property accessors in supported environments...
window._conditional_flag = 0;
Object.defineProperty(window, "ConditionalFlag", {
get: function() { return window._conditional_flag},
set: function(v) { console.log("changed"); window._conditional_flag = v; }
});
There's no "event" that gets triggered when a variable changes. JavaScript doesn't work that way.
When does this variable get changed? Just add a call to a function after it does.

Categories