Sunday, January 3, 2016

Installing Babel command line and playing with ES6

If you would like to play with ECMAScript6, you can install Babel CLI globally on your machine and run the babel-node command. babel-node is a version of the Node.js executable that understands ES6. It can be installed with the package manager NPM. Installation instructions are listed below.

1) Install two Node.js modules babel and babel-cli one after another. Note: if you have some troubles during installation, update your Node.js and NPM to the latest stable versions.

npm install --global babel
npm install --global babel-cli

2) Install a set of plugins for available ES6 (ES2015) features. Without these plugins you will get errors about unexpected token or similar. See http://babeljs.io/docs/plugins/preset-es2015/ for more details about supported ES6 features.

npm install --global babel-preset-es2015

3a) Start interactive REPL and type ES6 code. Note: globally installed modules on Windows are located under C:\Users\<Username>\AppData\Roaming\npm\node_modules, so that we need to put a complete path to them.

babel-node --presets C:\\Users\\Oleg\\AppData\\Roaming\\npm\\node_modules\\babel-preset-es2015
> let arr = [1,2,3]
> arr.map(x => x * x)
Output: [1,4,9]


3b) Alternative, you can place some ES6 code into a file, e.g. testes6.js, and let it run.

babel-node --presets C:\\Users\\Oleg\\AppData\\Roaming\\npm\\node_modules\\babel-preset-es2015 testes6.js
Output: [1,4,9]


In the example, babel-node is executed in the same directory where the file testes6.js is located.

Enjoy.

Wednesday, December 30, 2015

The best way for sharing data between controllers in AngularJS 1.x

You may know the situation in AngularJS 1.x when multiple independent controllers need to share some data. E.g. one controller adds some data that should be available in the other controllers in the same view. So far as I know there are three possibilities:
  • Using $scope, e.g. $scope of a common parent controller or $rootScope
  • Using publish-subscribe design pattern via $emit / $broadcast (fire events) and $on (listen for events)
  • Using services which can be injected in multiple controllers.
The first possibility to share data via $scope is a bad idea. If you share data via scopes, you have to know controllers' parent-child relationship. That means, your controllers are tightly coupled and the refactoring is hard to master. Some AngularJS examples save the data on the $rootScope, but the pollution of $rootScope is not recommended. Keep the $rootScope as small as possible. The event based possibility to share data via $emit, $broadcast and $on is a better approach in comparison to scope based one. The controllers are loosely coupled. But there is a disadvantage as well - the performance. The performance is ok for a small application, but for a large application with hundreds of $on listeners, the AngularJS has to introspect all scopes in order to find the $on listeners that fit to the corresponsing $emit / $broadcast. From the architecture point there is a shortcoming as well - we still need scopes to register $emit, $broadcast and $on. Some people also say - communication details should be hidden for the same reason we keep $http hidden behind a service layer. There are 5 guidelines for avoiding scope soup in AngularJS. The last 5. rule is called Don't Use Scope To Pass Data Around. It advices against using scopes directly and against event based approach. Last but not least - think about the upcomming AngularJS 2. It doesn't have scopes!

In my opinion, the preferred way for sharing data between controllers in AngularJS 1.x is the third possibility. We can use services. A service can keep data or acts as event emitter (example is shown below). Any service can be injected into controllers, so that conrollers still don't know from each other and thus are loosely coupled. I will refactor and extend one example from this blog post. The author of this blog post implemented two controllers for two panes. In the left pane we can input some text and add it as an item to a list in the right pane. The list itself is placed in a service (service encapsulates the data). This is probably a good idea when you have different views or controllers in conditional ng-if. But if controllers exist in the same view and show their data at the same time, the list should reside in the controller for the right pane and not in the service. The list belongs to the second controller. This is my opinion, so I will move the list into the controller and also add a third "message controller" which is responsible for messages when user adds items to the list or removes them from the list. We thus have three controllers and one service. The idea is to apply the listener pattern (also known as observer) to the service. The service acts as event emitter. Every controller can fire an ADD or REMOVE operation and register a listener function to be notified when the operation is done. The added / removed item acts as data passed along with operation into all registered listeners for the given operation. The live example is implemented on Plunker.

The first picture shows the adding process (click on the button Add To List) with a message about the successfully added item.


The second picture shows the removing process (click on a link with x symbol) with a message about the successfully removed item.


The HTML part looks as follows:
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta content="IE=edge" http-equiv="X-UA-Compatible" />
    <script src="https://code.angularjs.org/1.4.8/angular.js"></script>
</head>

<body ng-app="app">
    <div ng-controller="MessageController as ctrlMessage" style="margin-bottom:20px;">
        <span ng-bind-html="ctrlMessage.message"></span>
    </div>

    <div ng-controller="PaneOneController as ctrlPaneOne">
        <input ng-model="ctrlPaneOne.item">
        <button ng-click="ctrlPaneOne.addItem(ctrlPaneOne.item)">Add To List</button>
    </div>

    <div ng-controller="PaneTwoController as ctrlPaneTwo" style="float:right; width:50%; margin-top:-20px;">
        <ul style="margin-top:0">
            <li ng-repeat="item in ctrlPaneTwo.list track by $index">
                {{item}}
                <a href style="margin-left:5px;" title="Remove" ng-click="ctrlPaneTwo.removeItem($index)">x</a>
            </li>
        </ul>
    </div>

    <script src="controller.js"></script>
    <script src="service.js"></script>
</body>
</html>
As you can see, there are three independent HTML div elements with ng-controller directive. The MessageController shows a message above. The PaneOneController keeps an input value and the function addItem(). The PaneTwoController keeps a list with all items and the function removeItem(). The controllers look as follows in details:
(function() {
    var app = angular.module('app', []);
    app.controller('PaneOneController', PaneOneController);
    app.controller('PaneTwoController', PaneTwoController);
    app.controller('MessageController', MessageController);

    /* first controller */
    function PaneOneController(EventEmitterListService) {
        var _self = this;
        this.item = null;

        this.addItem = function(item) {
            EventEmitterListService.emitAddItem(item);
            _self.item = null;
        }
    }

    /* second controller */
    function PaneTwoController($scope, EventEmitterListService) {
        var _self = this;
        this.list = [];

        this.removeItem = function(index) {
            var removed = _self.list.splice(index, 1);
            EventEmitterListService.emitRemoveItem(removed[0]);
        }

        EventEmitterListService.onAddItem('PaneTwo', function(item) {
            _self.list.push(item);
        });

        $scope.$on("$destroy", function() {
            EventEmitterListService.clear('PaneTwo');
        });
    }

    /* third controller */
    function MessageController($scope, $sce, EventEmitterListService) {
        var _self = this;
        this.message = null;

        EventEmitterListService.onAddItem('Message', function(item) {
            _self.message = $sce.trustAsHtml("<strong>" + item + "</strong> has been added successfully");
        });

        EventEmitterListService.onRemoveItem('Message', function(item) {
            _self.message = $sce.trustAsHtml("<strong>" + item + "</strong> has been removed successfully");
        });

        $scope.$on("$destroy", function() {
            EventEmitterListService.clear('Message');
        });
    }
})();
All three controllers communicate with a service called EventEmitterListService. The service exposes three methods:
  • emitAddItem - notifies listeners that are interested in adding an item to the list. The item is passed as parameter.
  • emitRemoveItem - notifies listeners that are interested in removing an item from the list. The item is passed as parameter.
  • onAddItem - registers a listener function that is interested in adding an item to the list. The listener is passed as parameter.
  • onRemoveItem - registers a listener function that is interested in removing an item from the list. The listener is passed as parameter.
  • clear - removes all registered listeners which belong to the specified controller. The controller is identified by the scope parameter (simple unique string).
The clear method is important when the $scope gets destroyed (e.g. when the DOM associated with the $scope gets removed due to ng-if or view switching). This method should be invoked on $destroy event - see code snippets with $scope.$on("$destroy", function() {...}). The full code of the service is listed below:
(function() {
    var app = angular.module('app');
    app.factory('EventEmitterListService', EventEmitterListService);

    function EventEmitterListService() {
        // Format of any object in the array:
        // {scope: ..., add: [...], remove: [...]}
        // "scope": some identifier, e.g. it can be the part of controller's name
        // "add": array of listeners for the given scope to be notified when an item is added
        // "remove": array of listeners for the given scope to be notified when an item is removed
        var listeners = [];

        function emitAddItem(item) {
            emitAction('add', item);
        }

        function onAddItem(scope, listener) {
            onAction('add', scope, listener);
        }

        function emitRemoveItem(item) {
            emitAction('remove', item);
        }

        function onRemoveItem(scope, listener) {
            onAction('remove', scope, listener);
        }

        function clear(scope) {
            var index = findIndex(scope);
            if (index > -1) {
                listeners.splice(index, 1);
            }
        }

        function emitAction(action, item) {
            listeners.forEach(function(obj) {
                obj[action].forEach(function(listener) {
                    listener(item);
                });
            });
        }

        function onAction(action, scope, listener) {
            var index = findIndex(scope);
            if (index > -1) {
                listeners[index][action].push(listener);
            } else {
                var obj = {
                    'scope': scope,
                    'add': action == 'add' ? [listener] : [],
                    'remove': action == 'remove' ? [listener] : []
                }
                listeners.push(obj);
            }
        }

        function findIndex(scope) {
            var index = -1;
            for (var i = 0; i < listeners.length; i++) {
                if (listeners[i].scope == scope) {
                    index = i;
                    break;
                }
            }

            return index;
        }

        var service = {
            emitAddItem: emitAddItem,
            onAddItem: onAddItem,
            emitRemoveItem: emitRemoveItem,
            onRemoveItem: onRemoveItem,
            clear: clear
        };

        return service;
    }
})();
That's all. Happy New Year!

Wednesday, December 23, 2015

Mock responses to HTTP calls with network traffic simulation by using ngMockE2E

The AngularJS' module ngMockE2E allows to fake HTTP backend implementation for unit testing and to respond with static or dynamic responses via the when API and its shortcuts (whenGET, whenPOST, etc). In this post, I will only demonstrate how to respond to any HTTP calls by mocking the responses. We will also see how the network load can be simulated. Such behavior gives a feeling of real remote calls. The implemented example is available on Plunker. It shows a small CRUD application to manage imaginary persons. There are four buttons for sending AJAX requests in a REST like manner. When a request is sent, you can see the text Loading... which disappears after 2 seconds when the response "is arrived". In fact, no request is sent of course. This is just a simulation with the AngularJS' module ngMockE2E. The network load takes exactly 2 seconds but you can set another delay value if you want


The first button sends a GET request to /persons to receives all available persons. If you click on this button, you will see three persons received from the imaginary backend.


The second button sends a GET request to /person/:id to receives one person by its ID. The ID is appended to the URI part /person/. If you type e.g. 2 and click on this button, you should see the following person


There is also a proper validation. If you type e.g. 4, no person will be found because no person with the ID 4 exists in "the backend".


If you type some wrong ID which is not a numeric value, an error message will be shown as well.


The third button sends a POST request to /person to create a new person or update existing one. The input fields name and birthday are required. You can type a name and birthday for a new person, sends the POST request and see the created person recived from "the backend".


Now, if you sends a GET request to /persons (the first button), you should see the created person in the list of all persons.


The last button deletes a person by sending the DELETE request to /person/:id. The deleted person is shown above the buttons.


Click on the first button again to ensure that the person was deleted and doesn't exist more.


Let's show the code. First of all you have to include the file angular-mocks.js after the file angular.js in order to overwrite the original $httpBackend functionality.
<script src="https://code.angularjs.org/1.4.8/angular.js"></script>
<script src="https://code.angularjs.org/1.4.8/angular-mocks.js"></script>
What is $httpBackend? In AngularJS, we normally use a high level $http or $resource service for HTTP calls. These services use for their part a low level service called $httpBackend. The $httpBackend has useful methods to create new backend definitions for various request types. There is a method when(method, url, [data], [headers], [keys]) and many shortcut methods such as
  • whenGET(url, [headers], [keys])
  • whenHEAD(url, [headers], [keys])
  • whenDELETE(url, [headers], [keys])
  • whenPOST(url, [data], [headers], [keys])
  • whenPUT(url, [data], [headers], [keys])
  • ...
The most interesting parameter is the url. This can be a String like /persons, a regular expression like /^\/person\/([0-9]+)$/ for /person/:id or a function that receives the url and returns true if the url matches the current definition. These methods return an object with respond and passThrough functions that control how a matched request is handled. The passThrough is useful when the backend REST API is ready to use and you want to pass mocked request to the real HTTP call. In this example, we only use the respond. The respond can take the object to be returned, e.g. $httpBackend.whenGET('/persons').respond(persons) or a function function(method, url, data, headers, params) which returns an array containing response status (number), response data (string), response headers (object), and the text for the status (string). The file app.js demonstrates how to use the $httpBackend.
(function() {
    var app = angular.module('app', ["ngMockE2E"]);
    app.run(HttpBackendMocker);

    // original list of persons
    var persons = [
      {id: 1, name: 'Max Mustermann', birthdate: '01.01.1970'},
      {id: 2, name: 'Sara Smidth', birthdate: '31.12.1982'},
      {id: 3, name: 'James Bond', birthdate: '05.05.1960'}
    ];

    // Reg. expression for /person/:id
    var regexPersonId = /^\/person\/([0-9]+)$/;

    function HttpBackendMocker($httpBackend) {
        // GET /persons
        $httpBackend.whenGET('/persons').respond(persons);

        // GET /person/:id
        $httpBackend.whenGET(regexPersonId).respond(function(method, url) {
            var id = url.match(regexPersonId)[1];
            var foundPerson = findPerson(id);

            return foundPerson ? [200, foundPerson] : [404, 'Person not found'];
        });

        // POST /person
        $httpBackend.whenPOST('/person').respond(function(method, url, data) {
            var newPerson = angular.fromJson(data);
            // does the person already exist?
            var existingPerson = findPerson(newPerson.id);

            if (existingPerson) {
                // update existing person
                angular.extend(existingPerson, newPerson);
                return [200, existingPerson];
            } else {
                // create a new person
                newPerson.id = persons.length > 0 ? persons[persons.length - 1].id + 1 : 1;
                persons.push(newPerson);
                return [200, newPerson];
            }
        });

        // DELETE: /person/:id
        $httpBackend.whenDELETE(regexPersonId).respond(function(method, url) {
            var id = url.match(regexPersonId)[1];
            var foundPerson = findPerson(id);

            if (foundPerson) {
                persons.splice(foundPerson.id - 1, 1);
                // re-set ids
                for (var i = 0; i < persons.length; i++) {
                    persons[i].id = i + 1;
                }
            }

            return foundPerson ? [200, foundPerson] : [404, 'Person not found'];
        });

        // helper function to find a person by id
        function findPerson(id) {
            var foundPerson = null;
            for (var i = 0; i < persons.length; i++) {
                var person = persons[i];
                if (person.id == id) {
                    foundPerson = person;
                    break;
                }
            }

            return foundPerson;
        }
    }
})();
Now we need a custom service that encapsulates the $http service. The service will get the name DataService. It is placed in the file service.js.
(function() {
    var app = angular.module('app');
    app.factory('DataService', DataService);

    function DataService($http) {
        var service = {
            getPersons: getPersons,
            getPerson: getPerson,
            addPerson: addPerson,
            removePerson: removePerson
        };

        return service;

        function getPersons() {
            return $http.get('/persons').then(
                function(response) {
                    return response.data;
                },
                function(error) {
                    // do something in failure case
                }
            );
        }

        function getPerson(id) {
            return $http.get('/person/' + id).then(
                function(response) {
                    return response.data;
                },
                function(error) {
                    if (error.status && error.status === 404) {
                        return error.data;
                    } else {
                        return "Unexpected request";
                    }
                }
            );
        }

        function addPerson(person) {
            return $http.post('/person', person).then(
                function(response) {
                    return response.data;
                },
                function(error) {
                    // do something in failure case
                }
            );
        }

        function removePerson(id) {
            return $http.delete('/person/' + id).then(
                function(response) {
                    return response.data;
                },
                function(error) {
                    if (error.status && error.status === 404) {
                        return error.data;
                    } else {
                        return "Unexpected request";
                    }
                }
            );
        }
    }
})();
The service DataService is invoked by a controller which I named DataController and placed in the controller.js.
(function() {
    var app = angular.module('app');
    app.controller('DataController', DataController);

    function DataController($scope, DataService) {
        var _self = this;
        this.persons = [];
        this.personId = null;
        this.person = {};
        this.message = null;
        this.loading = false;

        this.getPersons = function() {
            init();

            DataService.getPersons().then(function(data) {
                _self.persons = data;
                _self.loading = false;
            })
        }

        this.getPerson = function(id) {
            // check required input
            if ($scope.form.id4get.$error.required) {
                _self.message = "Please add person's id";
                return;
            }

            init();

            DataService.getPerson(id).then(function(data) {
                if (typeof data === "string") {
                    // error
                    _self.message = data;
                    _self.persons = null;
                } else {
                    _self.persons = [data];
                }

                _self.loading = false;
            })
        }

        this.addPerson = function(person) {
            // check required input
            if ($scope.form.name.$error.required) {
                _self.message = "Please add person's name";
                return;
            }
            if ($scope.form.birthdate.$error.required) {
                _self.message = "Please add person's birthdate";
                return;
            }

            init();

            DataService.addPerson(person).then(function(data) {
                _self.persons = [data];
                _self.loading = false;
            })
        }

        this.removePerson = function(id) {
            // check required input
            if ($scope.form.id4delete.$error.required) {
                _self.message = "Please add person's id";
                return;
            }

            init();

            DataService.removePerson(id).then(function(data) {
                if (typeof data === "string") {
                    // error
                    _self.message = data;
                    _self.persons = null;
                } else {
                    _self.persons = [data];
                }

                _self.loading = false;
            })
        }

        // helper function to reset internal state
        var init = function() {
            _self.persons = [];
            _self.message = null;
            _self.loading = true;
        }
    }
})();
Now we can use the controller in the view - the file index.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta content="IE=edge" http-equiv="X-UA-Compatible" />
    <script src="https://code.angularjs.org/1.4.8/angular.js"></script>
    <script src="https://code.angularjs.org/1.4.8/angular-mocks.js"></script>
</head>
<body ng-app="app">
    <div ng-controller="DataController as ctrl" ng-cloak>
        <ul style="padding-left:0; list-style:none;">
            <li ng-repeat="person in ctrl.persons">
                {{person.id}} - {{person.name}} - {{person.birthdate}}
            </li>
        </ul>

        <div style="margin-bottom:15px;" ng-show="ctrl.loading">Loading ...</div>
        <div style="color:red; margin-bottom:15px;" ng-show="ctrl.message">{{ctrl.message}}</div>

        <form name="form" novalidate>
            <button ng-click="ctrl.getPersons()">GET /persons</button>
            <p></p>
            <button ng-click="ctrl.getPerson(ctrl.personId)">GET /person/:id</button>
            <input ng-model="ctrl.personId" name="id4get" required placeholder="id" />
            <p></p>
            <button ng-click="ctrl.addPerson(ctrl.person)">POST /person</button>
            <input ng-model="ctrl.person.name" name="name" required placeholder="name" />
            <input ng-model="ctrl.person.birthdate" name="birthdate" required placeholder="birthdate" />
            <p></p>
            <button ng-click="ctrl.removePerson(ctrl.personId)">DELETE /person/:id</button>
            <input ng-model="ctrl.personId" name="id4delete" required placeholder="id" />
        </form>
    </div>

    <script src="app.js"></script>
    <script src="config.js"></script>
    <script src="service.js"></script>
    <script src="controller.js"></script>
</body>
</html>
The current implementation has one shortcoming. The text Loading ... is not shown at all because the response is delivered very quickly, so that user doesn't see it. It would be nice to delay HTTP calls in order to simulate the network load. For this purpose we can use the $provide service and register a service decorator for the $httpBackend. The service decorator acts as proxy. If you look into the source code of the $httpBackend, you can see that the $httpBackend is created by the constructor function(method, url, data, callback, headers, timeout, withCredentials). The four parameter callback is responsible for the response. We have to provide our own implementation which I named delayedCallback. The delayedCallback function invokes the original callback with a delay (here 2 seconds) by means of setTimeout(). We delegate the proxy call to the $httpBackend instantiation, but with the new delayed callback. The injected $delegate object points exactly to the $httpBackend. The full code is shown below.
(function() {
    var app = angular.module('app');
    app.config(HttpBackendConfigurator);

    function HttpBackendConfigurator($provide) {
        $provide.decorator('$httpBackend', HttpBackendDecorator);

        function HttpBackendDecorator($delegate) {
            var proxy = function(method, url, data, callback, headers, timeout, withCredentials) {
                // create proxy for callback parameter
                var delayedCallback = function() {
                    // simulate network load with 2 sec. delay
                    var delay = 2000;

                    // Invoke callback with delaying
                    setTimeout((function() {
                        callback.apply(this, arguments[0]);
                    }.bind(this, arguments)), delay);
                };

                // delegate to the original $httpBackend call, but with the new delayed callback
                $delegate(method, url, data, delayedCallback, headers, timeout, withCredentials);
            };

            // the proxy object should get all properties from the original $httpBackend object 
            angular.extend(proxy, $delegate);

            // return proxy object
            return proxy;
        }
    }
})();

Tuesday, October 27, 2015

PrimeFaces Extensions 4.0.0 released

Dear Community,

A new 4.0.0 version of PrimeFaces Extensions has been released. Artefacts are available in the Maven central.

Release notes there are as usually on the project's wiki page.

This version is fully compatible with the latest PrimeFaces 5.3.

Enjoy.

Monday, September 21, 2015

Promises in AngularJS. Part I. Basics.

There are many blog posts about Promises in general and Promises in AngularJS in particular. Promises are a part of the ES6 (EcmaScript 6) specification, so it is worth to learn them. In this blog post, I will try to summarize the most important info about Promises in a simple and clear way. The necessary code snippets will be provided too. The first part is about basics.

What is a Promise? Promise is a solution to avoid so-called "Pyramid of Doom". If you work with asynchronous operations (HTTP calls, file system operations, etc.), you know the situation where you have callbacks nested inside of another callbacks which are nested again inside of callbacks and so on. An example:
asyncOperationOne('first data', function(firstResult) {
    asyncOperationTwo('second data', function(secondResult) {
        asyncOperationThree('third data', function(thirdResult) {
            asyncOperationFour('fourth data', function(fourthResult) {
                doSomething();
            });
        });
    });
});
Every asynchronous operation invokes a callback function when the operation is completely done. In case of AngularJS and the $http service the "Pyramid of Doom" could look as follows:
var result = [];

$http.get('/api/data/first.json').success(function(data) {
    result.push(data);
    $http.get('/api/data/second.json').success(function(data) {
        result.push(data);
        $http.get('/api/data/third.json').success(function(data) {
            result.push(data);
            $scope.result = result;
        });
    });
});
We didn't show yet the error handling. Now imagine how it looks like with error handling. Terrible and not readable. Promises help to synchronize multiple asynchronous functions and avoid Javascript callback hell. The official concept of Promises is described in the Promises/A+ specification. With promises, an asynchronous call returns a special object called Promise. The calling code can then wait until that promise is fulfilled before executing the next step. To do so, the promise has a method named then, which accepts two functions - success and error function. The success function will be invoked when the promise has been fulfilled. The error function will be invoked when the promise has been rejected. An example of $http service based on promises:
$http.get('/api/data.json').then(
    function(response) {
        ...
    },
    function(error) {
        ...
    }
);
We can say, a promise represents the future result of an asynchronous operation. The real power from promises is the chaining. You can chain promises. The then function returns a new promise, known as derived promise. The return value of some promise's callback is passed as parameter to the callback of the next promise. In this way, you can access previous promise results in a .then() chain. An error is passed too, so that you can define just one error callback at the end of chain and handle all errors there. Here is an example of promise chaining:
$http.get('/api/data.json').then(
    function(response) {
        return doSomething1(response);
    })
    .then(function(response) {
        return doSomething2(response);
    })
    .then(function(response) {
        return doSomething3(response);
    }, function(error) {
        console.log('An error occurred!', error);
    }
);
If you return some value from the derived promise as shown above, the derived promise will be resolved immediately. A derived promise can be deferred as well. That means, the resolution / rejection of the derived promise can be deferred until the previous promise has been resolved / rejected. This is done by returning a promise from the success or error callback. The AngularJS' $http service returns a promise, so that we can rewrite the shown above "Pyramid of Doom" with $http as
$http.get('/api/data/first.json').then(
    function(response) {
        // response here comes from the GET to /api/data/first.json
        result.push(response.data);
        return $http.get('/api/data/second.json');
    })
    .then(function(response) {
        // response here comes from the GET to /api/data/second.json
        result.push(response.data);
        return $http.get('/api/data/third.json');
    })
    .then(function(response) {
        // response here comes from the GET to /api/data/third.json
        result.push(response.data);
        $scope.result = result;
    }, function(error) {
        console.log('An error occurred!', error);
    }
);
What happens now when a HTTP call in the promise chain fails? In this case, success callbacks in every subsequent promise in the chain will be skipped (not invoked). The next error callback in the promise chain however will be invoked. Therefore, the error callback is indispensable. An example:
$http.get('/api/data/wrong_or_failed_url.json').then(
    function(response) {
        // this function is not invoked
        return $http.get('/api/data/second.json');
    })
    .then(function(response) {
        // this function is not invoked
        return $http.get('/api/data/third.json');
    })
    .then(function(response) {
        // this function is not invoked
        $scope.result = response.data;
    }, function(error) {
        // error callback gets invoked
        console.log('An error occurred!', error);
    }
);
Instead of error callback you can also use an equivalent - promise's function catch. The construct promise.catch(errorCallback) is a shorthand for promise.then(null, errorCallback).

Be aware that either the success or the error callback will be invoked, but never both. What to do if you need to ensure a specific function always executes regardless of the result of the promise? You can do this by registering that function on the promise using the finally() method. In this method, you can reset some state or clear some resources. An example:
$http.get('/api/data.json').then(
    function(response) {
        // Do something in success case
    },
    function(error) {
        // Do something in failure case
    }).finally(function() {
        // Do something after either success or failure
    }
);
Where and how to use the promise examples above? A typical pattern in AngularJS is to have calls via $http in a service. Controllers call services and are not aware that $http is used. Example for MyController -> MyService -> $http:
// In MyService
this.fetchData = function() {
    return $http.get('/api/data.json');
};

// In MyController
$scope.fetchData = function() {
    MyService.fetchData().then(function(response) {
        return response.data;
    }, function(error) {
        ...
    }).finally(function() {
        ...
    })
};
We have to mention yet that AngularJS' implementation of promises is a subset of the library Q. Q is the most known implementation of the Promises/A+ specification. That's all for this short post. In the next post, we will meet the AngularJS' deferred object. A deferred object is an object that exposes a promise as well as the associated methods for resolving / rejecting that promise. It is constructed using the $q service - the AngularJS' implementation of promises / deferred objects inspired by Q.

Stay tuned!