Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJs $q.defer() not working

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?

like image 683
trajce Avatar asked Aug 23 '14 15:08

trajce


People also ask

What is Q defer () in AngularJS?

$q. defer() allows you to create a promise object which you might want to return to the function that called your login function.

What does $q do in Angular?

$q is integrated with the $rootScope.Scope Scope model observation mechanism in AngularJS, which means faster propagation of resolution or rejection into your models and avoiding unnecessary browser repaints, which would result in flickering UI.

What is promises in AngularJS?

Promises in AngularJS are provided by the built-in $q service. They provide a way to execute asynchronous functions in series by registering them with a promise object. {info} Promises have made their way into native JavaScript as part of the ES6 specification.

What is .then in AngularJS?

then() function to handle the callbacks. Traditional promises (using the $q Service in Angular) have a . then() function to provide a continuation on success or failure, and . then() receives parameters for a success and failure callback.


2 Answers

The 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.

like image 120
Benjamin Gruenbaum Avatar answered Oct 07 '22 20:10

Benjamin Gruenbaum


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.org/api/ng/service/$q

like image 44
Vamsi Avatar answered Oct 07 '22 20:10

Vamsi