In my Javascript code I am trying to set up this code
if(this.boolean == true) {
setTimeout(function(){ this.boolean = false; }, 2000);
}
But for some reason it won't work, the boolean just remains true. How can I fix this/what can I do instead?
The setTimeout works with other lines of code but weirdly not this one.
this behaves in a special way in JavaScript.
Change
setTimeout(function(){ this.boolean = false; }, 2000);
to
setTimeout(() => { this.boolean = false; }, 2000);
and the this keyword will be interpreted block-scoped.
It's because of "this" - you can use a closure to do this:
var x = this;
var onTimeout = function(){
x.boolean = false;
}
if(this.boolean == true) {
setTimeout(onTimeout, 2000);
}
"this" is not what you think it is inside the setTimeout function:
setTimeout and "this" in JavaScript
If you have ES6 available, arrow functions use their lexical scope for this
var onTimeout = () => this.boolean = false;
setTimeout(onTimeout , 2000);
More about that here:
https://medium.com/tfogo/advantages-and-pitfalls-of-arrow-functions-a16f0835799e
If you are not using arrow function, the this variable will be the one from setTimeout and not your main class because of its scope.
The following should resolve the issue.
if(this.boolean == true) {
setTimeout(() => { this.boolean = false; }, 2000);
}
Functions have their own this, so this.boolean inside of function implies that you are trying to change the property boolean of the function itself. On the other hand, if you use arrow functions, you can avoid that because arrow functions don't have their own this.
setTimeout(() => { this.boolean = false }, 2000)
The scope of "this" is changed in your function inside the setTimeout.
You could use the arrow function like other commenters have said.
Or, you can set a var as this, and then use that var in the functions inside the SetTimeout.
var coolThis = this;
if(coolThis.boolean == true) {
setTimeout(function(){ coolThis.boolean = false; }, 2000);
}
Related
I would like to know if there is a way to use setTimeout recursive implements with an arrow function, in order to use this (refers to my class attribute for example) inside. Indeed, this = undefined when i declare my setTimeout with a normal function
I got :
public currentIndex: number = 0;
setTimeout(function run(){
this.currentIndex++;
console.log(this.currentIndex); // returns undefined
setTimeout(run, 1000);
}, 1000)
Instead of :
setTimeout(() => {
this.currentIndex++;
console.log(this.currentIndex) // returns currentIndex value
setTimeout( ?? , 1000) // What should i put instead of '??' ?
}, 1000)
You could bind this first and then use this function for all calls.
function run(reference) {
this.currentIndex++;
console.log(this.currentIndex); // returns undefined
setTimeout(reference, 1000, reference);
}
const runThis = run.bind(thisReference);
setTimeout(runThis, 1000, runThis);
Its because arrow function does not create new context inside arrow function body but normal function does. So this in arrow function refers to parent scope context but this in normal function refers to its own context.
This will create setTimeouts recursively
let currentIndex = 0;
const run = () => {
setTimeout(() => {
currentIndex++;
console.log(currentIndex);
run();
}, 1000);
}
run();
but better approach may be (I don't know your use case, so it is just maybe) to use setInterval()
let currentIndex = 0;
const interval = setInterval(() => {
currentIndex++;
console.log(currentIndex);
// stop interval
if (currentIndex >= 10) {
clearInterval(interval);
}
}, 1000);
Probably the easiest way is to extract the arrow function into its own variable:
const run = () => {
this.currentIndex++;
console.log(this.currentIndex);
setTimeout(run, 1000);
};
setTimeout(run, 1000);
Though in this particular example you could simplify it even more using setInterval instead of setTimeout, avoiding the second setTimeout call entirely.
I am executing the function delayFilter() on keyup of an input box. I want to delay 1 second after the user stops typing and run the function filterProducts(). However, when executing filterProducts() inside of the setTimeout I get the console error "this.filterProducts is not a function". This function gets called fine when outside of the setTimeout. Why is this error being thrown?
delayFilter() {
let timeout = null;
clearTimeout(timeout);
timeout = setTimeout(function() {
this.filterProducts();
}, 1000);
}
filterProducts() {
//do stuff
}
That is because these, this inside the callback, does not refer to the object outside.
Try this:
delayFilter() {
let timeout = null;
clearTimeout(timeout);
let self = this;
timeout = setTimeout(function() {
self.filterProducts();
}, 1000);
}
filterProducts() {
//do stuff
}
You can also try the arrow function. The reason can be seen here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
An arrow function expression is a syntactically compact alternative to a regular function expression, although without its own bindings to the this, arguments, super, or new.target keywords.
delayFilter() {
let timeout = null;
clearTimeout(timeout);
timeout = setTimeout(() => {
this.filterProducts();
}, 1000);
}
filterProducts() {
//do stuff
}
You need to bind the scope of the function in the setTimeout callback. the easiest way is to use arrow functions, if your platform supports it.
timeout = setTimeout(() => this.filterProducts(), 1000);
you can also save the scope in a variable.
var self = this;
timeout = setTimeout(funciton() { self.filterProducts() }, 1000);
Alternatively you can manually bind it. This is useful if you want to pass the function around.
timeout = setTimeout(function() {...}.bind(this), 1000);
How can I use the setTimeout() function in a Vue.js method?
I have already tried something like this, but it doesn't work:
fetchHole: function () {
//get data
},
addHole: function () {
//my query add new
setTimeout(function () { this.fetchHole() }, 1000)
},
I get this error message: Uncaught TypeError: this.fetchHole is not a function
Add a bind() call to your function declaration:
setTimeout(function () { this.fetchHole() }.bind(this), 1000)
so that your Vue component's this is accessible within the function.
Side note: #nospor's accepted answer is cleaner in this particular situation. The bind approach is a bit more generalized - very useful if you want to do an anonymous function, for example.
The classic issue with contextual this in JavaScript.
The following part of code shows an easy solution - if you are using ES6 with Vuejs (default config with vuecli y babel). Use an arrow function
setTimeout(()=>{
this.yourMethod()
},1000);
An arrow function does not have its own this. The this value of
the enclosing lexical scope is used;
Arrow functions - JavaScript | MDN
Try this: setTimeout(this.fetchHole, 1000) because this in anonymous function is attached to that anonymous function not to your main function
I think this works too.
var self = this;
setTimeout(function () { self.fetchHole() } , 1000)
Call recursive with TimeOut:
save: function () {
this.progressToProced = 0
this.progress()
},
progress: function () {
if (this.progressToProced < 100) {
this.progressToProced++
setTimeout(function () { this.progress() }.bind(this), 100)
}
}
You can try :
addHole:function(){
let vm = this
setTimeout(function(){vm.fetchHole()}, 1000)
}
I have the following function in my controller. When i try to add the $timeout I get reference error as the toggle function comes as not defined. I am new to angular. Does anyone know why this happens?
$scope.toggleTrash = function(card) {
card.clickedtrash = card.clickedtrash ? false : true;
if (card.clickedtrash == true) {
$timeout(toggleTrash(card), 3000);
}
}
Angular's $timeout is just a wrapper for window.setTimeout. You can't pass a variable along with the function in the way that you're attempting. You can only do this:
$timeout(toggleTrash, 3000);
Maybe try creating an anonymous closure, so that the value of card is preserved when the callback executes. So:
$timeout(function() {
toggleTrash(card);
}, 3000);
You are getting the reference error because instead of using toggleTrash, you should use $scope.toggleTrash.
And use $timeout like:
$timeout(function () {
$scope.toggleTrash(card);
}, 3000);
I answered it with this:
$scope.toggleTrash = function(card) {
card.clickedtrash = true;
$timeout(function(){card.clickedtrash = false}, 4000);
};
I'm trying to figure out how I can reset a timer created inside of an immediately invoking function from within the setTimeout closure. Here is my function:
var triggerHeightRecalc = function() {
setTimeout(function() {
if(imagesLoaded()) {
adjustHeight();
} else {
triggerHeightRecalc();
}
}, 100);
}();
In the event that imagesLoaded() returns false, I receive the following error from attempting to call triggerHeightRecalc():
Uncaught TypeError: undefined is not a function
So I'm not sure if the issue is the function is not in the scope, or maybe it just cannot call itself? I've tried passing triggerHeightRecalc as a parameter in the setTimeout closure, but that doesn't seem to work either.
I've also tried this after reading this SO question:
var triggerHeightRecalc = function() {
var that = this;
var callback = function() {
if(imagesLoaded()) {
adjustHeight();
} else {
that.triggerHeightRecalc();
}
};
timeDelay = window.setTimeout(callback, 100);
}();
What am I doing wrong here, or is there a better way? Is this something that should be a setInterval() instead and I clear the interval when images are loaded?
Side Note: I'm calculating the height of a div inside a jQuery plugin, but I need to wait until the images are loaded in order to get the correct height (not sure if that is relevant).
Since you are invoking the function right from the declaration triggerHeightRecalc is getting set to the return of that function call, which is undefined since you in fact do not return anything.
You can do two things
1. Declare then invoke
var triggerHeightRecalc = function() {
setTimeout(function() {
if(imagesLoaded()) {
adjustHeight();
} else {
triggerHeightRecalc();
}
}, 100);
};
triggerHeightRecalc();
2. Wrap the declaration in () and invoke
var triggerHeightRecalc;
(triggerHeightRecalc = function() {
setTimeout(function() {
if(imagesLoaded()) {
adjustHeight();
} else {
triggerHeightRecalc();
}
}, 100);
})();
The second one will create a global variable unless you do the var triggerHeightRecalc; before hand.
Already answered, but I'll put this in.
First of all, if you just want to wait until all images have loaded you can use:
https://github.com/desandro/imagesloaded and then run the above code.
If that's not what you want, and you you just want a function that your setTimeout can run, then you can remove the () at the end of the function.
Here is what's happening in your current code
Your function is missing the opening bracket or similar character !+( (function.
Also your IIFE has no return keyword, and will return undefined to triggerHeightCalc.
If you do want an IIFE then you can either have a private version that is only callable within itself.
(function myModule(){
myModule(); //calls itself
})();
Or a public version that can be called both inside and outside.
var myModule = (function(){
return function myMod(){
myMod();
}
})();
myModule();
Patrick Evans has the right reasons, but there is a neater way to solve it :)
(function triggerHeightRecalc() {
setTimeout(function() {
if(imagesLoaded()) {
adjustHeight();
} else {
triggerHeightRecalc();
}
}, 100);
})();
Here you are give an internal name to the (still) anonymous function. The name is only visible from within the function itself, its not visible in the global scope. Its called a Named function expression.