Sunday, February 22, 2015

Promises and AngularJS $q Service

Before continuing, one must understand the concept of promises (and deferreds). For some reason, this topic seems to take one awhile to absorb, especially if one has using the traditional JavaScript callback strategy allot.

The following is an excellent introduction to the topic:
<http://www.webdeveasy.com/javascript-promises-and-angularjs-q-service/>

No, really read the tutorial before continuing...

For a real example of why we need promises, one can look at a bit of old code that I did where I had to repeatedly had to reset the indenting as things were getting heavily nested.
<https://github.com/larkintuckerllc/introduce/blob/master/public/app/controllers/meeting.js>

First, let review the call back chain that we are looking to replace in the section "app/controllers/wineriesCtrl.js"

JavaScript
    myDataRef.child('wineries').once('value', function(snapshot) {
        $timeout(function() {
            ctrl.wineries = Object.keys(snapshot.val()).map(function(key) {
                return {key: key, val: snapshot.val()[key]};
            });
        });
    }, function(error) {
    });

Here we two asynchronous functions "once" and "$timeout"; as a reminder, the "$timeout" call is needed as AngularJS does not alerted when the Firebase call returns and thus would not update the DOM.

We are going to first wrap the "once" function to another function that returns a promise.

JavaScript
    function onceValuePromise(ref) {
        var deferred = $q.defer();
        ref.once('value', function(snapshot) {
            deferred.resolve(snapshot);
        }, function(error) {
            deferred.reject(error);
        });
        return deferred.promise;
    };

Then we use the "onceValuePromise" function as follows:

JavaScript
onceValuePromise(myDataRef.child('wineries'))
    .then(function(snapshot) {
        ctrl.wineries = Object.keys(snapshot.val()).map(function(key) {
            return {key: key, val: snapshot.val()[key]};
        });
    })
    .catch(function() {
    });

Ok, this is not a terribly impressive example of having promises simplify the code (mostly because this particular code is fairly simple).  One immediate benefit, however, is that $timeout is no longer needed as using promises with $q automatically alert AngularJS to update the DOM.

No comments:

Post a Comment