I had some problems with $q.defer();
When I used callbacks instead, my code was working(the view was updated), but with $q.defer();
it's not.
This is my code:
The service:
eventsApp.factory('eventData', function($http, $q) {
return {
getEvent: function(callback) {
var deferred = $q.defer();
$http({method: 'GET', url: '/node/nodejsserver/server.js'}).
success(function(data, status, headers, config){
//callback(data.event);
deferred.resolve(data.event);
console.log('status: ', status, ' data: ', data);
}).
error(function(data, status, headers, config){
deferred.reject(status);
console.log('status: ', status);
});
return deferred.promise;
}
};
});
The controller:
eventsApp.controller('EventController',
function EventController($scope, eventData) {
$scope.event = eventData.getEvent();
}
);
But it doesn't work.
Then I found this answer and I updated my controller like this:
eventsApp.controller('EventController',
function EventController($scope, eventData) {
eventData.getEvent().then(function(result) {
$scope.event = result;
});
}
);
and it works.
What is the difference between the nonworking and the working code?
I had some problems with $q.defer();
When I used callbacks instead, my code was working(the view was updated), but with $q.defer();
it's not.
This is my code:
The service:
eventsApp.factory('eventData', function($http, $q) {
return {
getEvent: function(callback) {
var deferred = $q.defer();
$http({method: 'GET', url: '/node/nodejsserver/server.js'}).
success(function(data, status, headers, config){
//callback(data.event);
deferred.resolve(data.event);
console.log('status: ', status, ' data: ', data);
}).
error(function(data, status, headers, config){
deferred.reject(status);
console.log('status: ', status);
});
return deferred.promise;
}
};
});
The controller:
eventsApp.controller('EventController',
function EventController($scope, eventData) {
$scope.event = eventData.getEvent();
}
);
But it doesn't work.
Then I found this answer and I updated my controller like this:
eventsApp.controller('EventController',
function EventController($scope, eventData) {
eventData.getEvent().then(function(result) {
$scope.event = result;
});
}
);
and it works.
What is the difference between the nonworking and the working code?
2 Answers
Reset to default 11The non working code uses automatic promise unwrapping which was deprecated and removed in recent versions of Angular. It was deemed too magical.
Angular used to do the following when you returned a promise:
- Return an empty array.
- Populate it later on when the request arrives.
- Trigger a digest on its own.
This behavior was deemed confusing and magical by Angular developers and was deprecated (in 1.2), deactivated and soon (1.3) removed in Angular. The correct way to assign a value through a promise is like you've indicated in the second example:
eventData.getEvent().then(function(result) {
$scope.event = result;
});
From the Angular 1.3 (pending) release docs:
$parse: due to fa6e411d, promise unwrapping has been removed. It has been deprecated since 1.2.0-rc.3. It can no longer be turned on. Two methods have been removed:
And from the 1.2 release docs:
$parse and templates in general will no longer automatically unwrap promises.
Before:
$scope.foo = $http({method: 'GET', url: '/someUrl'});
<p>{{foo}}</p>
After:
$http({method: 'GET', url: '/someUrl'})
.success(function(data) {
$scope.foo = data;
});``
{{foo}}
`This feature has been deprecated. If absolutely needed, it can be reenabled for now via the $parseProvider.unwrapPromises(true) API.
While we're here avoid the deferred anti pattern, $http
already returns the promise so you can simply return
it rather than using $q.defer
.
Edit: check Benjamin's answer
In your service, you are returning a promise
object, promise object has .then
method.
you are assigning the promise
object to $scope.event
, so you wont get the data (in the latest version according to Benjamin)
when you resolve the promise using deferred.resolve(data.event)
then the function you passed as argument to .then
method will be called with this resolved data.
You can give a second argument to the .then
, which will be called when you do deferred.reject()
This is basic functionality of promise api. Just read the docs for more info https://docs.angularjs/api/ng/service/$q