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);
};
Related
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);
}
Is it possible to pass a callback function that does not exist yet? My goal is to have a common function that will wait for another callback function to exist, when it does exist, it should execute it. This is what I have so far, but I can't figure out how to pass the function in that doesn't exist as a function yet.
function RunTemplateFunction(callback, userInfo) {
if ($.isFunction(callback)) {
callback(userInfo);
} else {
var myInterval = setInterval(function () {
if ($.isFunction(callback)) {
clearInterval(myInterval);
callback(userInfo);
}
}, 200);
}
}
I run the function like this:
RunTemplateFunction(MyFunctionToRun, GetUserInfo());
I get MyFunctionToRun is undefined for obvious reasons, I also tried the workaround of passing the function as a string and then convert the string to a function using eval(). But that throws the same error. I also thought of using the new function(), but that actually creates a new function.
Any help is appreciated. thank you.
If you call RunTemplateFunction by undefined there is no way we can see, is callback is defined or not, as we don't have reference to anything.
If you can modify the declaration to accept object as below, we can achieve what we want
function RunTemplateFunction(options, userInfo) {
if ($.isFunction(options.callback)) {
console.log('called1',userInfo);
options.callback(userInfo);
} else {
var myInterval = setInterval(function () {
if ($.isFunction(options.callback)) {
console.log('Called dynamically!!');
clearInterval(myInterval);
options.callback(userInfo);
}
}, 200);
}
}
var options = {}
RunTemplateFunction(options,{user:122});
options.callback = function(){
console.log("I'm called!!");
}
This will print
Called dynamically!!
I'm called!!
EDIT:
We can also call callback function in following way without setInterval, it will look different but options.callback variable is replaced by template.callMe function and its instantaneous also.
function TemplateRunner(userInfo){
this.callMe = function(cb){
this.templateFunction(cb);
}
this.templateFunction = function(callback){
callback(userInfo);
}
}
var template = new TemplateRunner({user:100})
template.callMe(function(user){
console.log('call me1',user);
});
template.callMe(function(user){
console.log('call me2',user);
})
This will print
call me1 {user: 100}
call me2 {user: 100}
I was just wondering;
Why does this work;
test = function(message) {
console.log('xxx');
}
setTimeout(test, 3000);
but not this;
test = function(message) {
console.log(message);
}
setTimeout(test('xxx'), 3000);
I know it should be written like this;
But the version above would be so much more convenient...
test = function(message) {
console.log(message);
}
setTimeout(function() { test('xxx'); }, 3000);
You're assigning the returned result of test to the callback argument of setTimeout instead of passing the function reference.
function callback(callback) {
callback();
}
function say(message) {
console.log(message);
// this function doesn't return anything
}
// callback(say('Hello World!')) === callback() because say(message) doesnt return anything.
In your 2nd example it is immediately calling test with the string xxx.
You are calling the function immediatly in your second example. To pass the string, you can bind the parameter instead of calling it on its own:
setTimeout(test.bind(null,'xxxx'), 3000);
test = function(message) {
alert(message);
}
setTimeout(test.bind(null,'xxxx'), 3000);
If you write a function name with parenthesis, it will call it instead giving reference.
The second one doesn't work because setTimeout requires a function as a parameter (which it will call) and the second version you show has test('xxx') which means "the result of calling test('xxx')" which is undefined - not a function.
So i'm using angularJS and$q service. But for simplicity i'm using $timeout since it creates a promise.
Question:
Is it possible to only return a promise when a conditional has been satisfied? For this example, I want to wait for carousel.params.caruselReady to return true before I move to next .then.
$timeout(function(){
if(Carousel.params.ready()){
return ready;
}
},0).then(function(ready){
//...do stuff..//
}
Carousel.params.ready is coming from Carousel.js a factory:
//this function gets called everytime a image has been loaded. when all images are rendered than carousel is ready
carouselElLoaded: function (result) {
var count = 1;
Carousel.params.pageRenderedLength += count;
if (Carousel.params.pageRenderedLength >= Carousel.params.pageLength) {
Carousel.params.carouselReady = true;
}
},
Lastly, carouselElLoad is being called from wa.pages.js (a directive)
$img.onload = function (e) {
var self = this;
$timeout(function () {
return self;
}, 0).then(function () {
Carousel.set.carouselElLoaded(e);
});
};
Currently, I'm using a $watch to achieve this but I was wondering if I could accomplish the same w/o a watcher.
You can use a promise instead of a boolean flag and it will do exactly what you want.
In Carousel.js define a promise names isCarouselReady and resolve it once the carousel is ready, your code should like something like this:
// During the initialisation of your factory
var carouselDeferred = $q.defer()
Carousel.params.isCarouselReady = carouselDeferred.promise;
//this function gets called everytime a image has been loaded. when all images are rendered than carousel is ready
carouselElLoaded: function (result) {
var count = 1;
Carousel.params.pageRenderedLength += count;
if (Carousel.params.pageRenderedLength >= Carousel.params.pageLength) {
carouselDeferred.resolve(/* What ever you'd like here */);
}
},
Now you all you have to do in order to use it is:
Carousel.params.isCarouselReady.then(function() {
// Your logic
});
Your last part would be nicer if it would look something like this:
$img.onload = function (e) {
$scope.$apply(function(){
Carousel.set.carouselElLoaded(e);
});
};
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.