Relevant fiddle: https://jsfiddle.net/tqf4zea7/1/
I'm using $q in an angular controller. To test some scenarios, I created an array on the scope to push messages to:
$scope.messages = [];
I have set up a function that returns a $q function as so:
function returnAPromise(valToReturn){
return $q(function(resolve, reject){
$timeout(function(){
resolve(valToReturn);
}, 500);
});
}
I then have a .then()
call on the result that looks like this:
returnAPromise('third').then($scope.messages.push);
Since I only want to push the value that the promise was resolved with to the array, I figured I could just pass in the push method of the messages array, but when I do that, I get the following error:
VM289 angular.js:12520 TypeError: Array.prototype.push called on null or undefined
at processQueue (VM289 angular.js:14792)
at VM289 angular.js:14808
at Scope.$eval (VM289 angular.js:16052)
at Scope.$digest (VM289 angular.js:15870)
at Scope.$apply (VM289 angular.js:16160)
at VM289 angular.js:17927
at completeOutstandingRequest (VM289 angular.js:5552)
at VM289 angular.js:5829
If I enclose push in a function, it works fine:
returnAPromise('third').then(function(message){
$scope.messages.push(message)
});
Is this a closure issue I don't understand?
You need to bind push since it uses this
returnAPromise('third').then($scope.messages.push.bind($scope.messages));
I know there is an accepted answer, but i will explain this more clearly here
lets start with an example
var scope = {
scopeFn: function() {
console.log('this', this)
}
}
function callFn(fn) {
fn();
}
callFn(obj.scopeFn) // will log window object
callFn(function() {
obj.scopeFn();
});// will log scope object
as you can see, wrapping the function will give the called object the value of this, but calling it directly without wrapping it will call the window object.
this
will bind to the object its called from.
In the first example callFn(obj.scopeFn)
you are passing the function as a parameter, hence when the function is called, its called directly not from the scope
object. (scope
object is lost, only the function reference is sent).
in the second example you are calling the function scopeFn
from the object, hence the this
will bind to its object. (scope
object is not lost, as the whole thing is there when its called)
To solve this issue you need to bind the function you are passing as a parameter for the resolve, so it will always be called as if it is called from its parent object.
var scopeMessage = $scope.messages;
returnAPromise('third').then(scopeMessage.push.bind(scopeMessage));
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