AngularJs, Javascript

Using promise chaining and $q.when to create a complete and clean flow out of distributed unrelated API’s


Recently i had to develop a feature which utilized no less then 4 different API’s in a single flow. While this may sound complicated, the real challenge was integrating all of them into a clean angular flow, without relying on scope.$apply, safeApply, $digest, unnecessary watchers and all kind of white or black magic. Some of the API calls were synchronous and some were asynchronous, but all of them had to be executed in a chain, passing data to each other.

So – how should we take 4 completely unrelated libraries, exposing different API’s, and not only properly chain them, but also integrate them properly into our application flow?

First of all, $q.when

As angular documentation about $q explains $q.when:
Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise. This is useful when you are dealing with an object that might or might not be a promise, or if the promise comes from a source that can’t be trusted.

So what exactly does it means? If we’ll (extremely) simplify the explanation, it basically means that whichever value you’ll receive from a given 3rd party method, whether it’s a promise or a regular value, you will be able to handle it as you would have handled a regular $q promise resolution. On top of that, what the documentation does not mention, is that after the state is changed (wether it was resolved or rejected) – digest cycle is being triggered, eliminating the need for $scope.$apply.


So here you go, one line of code, one (and a half) line of explanation, and you have all your 3rd party API’s standing in line (literally) ready to be integrated into your application flow.

Now let’s wrap everything to a story-like flow execution

Since we used $q.when to wrap all our vendor methods, they are now chainable and can be executed in a very clear and self explanatory code.

Let’s see some of this code we are talking about:

HTML

<body ng-controller="AppController">

   <h1>Build a car</h1>

    {{car}}
  </body>



JavaScript

app.controller("AppController", function($scope, $q) {

  $scope.car = "Building my car...";

  // execute the car build flow.
  getCarShield()
    .then(getWheels)
    .then(getCarColor)
    .then(displayTheCar)
    .catch(function(err) {
      
      // catch an error if exists
      if (err) $scope.car = 'Could not finish building the car :<';
    });
    
    
  // wrap all of our 3rd party methods in $q.when,
  // this will allow then to be chainable and take normalize the return value,
  // wether its a promise or a value
  var getCarShield = function() {
      return $q.when(carShieldFromMechanic()).then(function(carShield) {
        return carShield;
      });
    },

    getWheels = function(carShield) {
      return $q.when(wheelsFromVendor(carShield)).then(function(wheelsType) {
        return wheelsType;
      });
    },

    getCarColor = function(shieldAndWheels) {
      return $q.when(paintTheCar(shieldAndWheels)).then(function(finalizedCar) {
        return finalizedCar;
      });
    },

    displayTheCar = function(car) {
      $scope.car = car;
    };

});

// get car shield from the mechanic
function carShieldFromMechanic() {
  return '2008 GT500';
}

// get wheels from wheels vendor
function wheelsFromVendor(carShield) {
  return carShield += " with 160/65r315 wheels";
}

// painting the car may take some time, so use jquery promise and notify me when it's done
function paintTheCar(shieldAndWheels) {

  var deferred = $.Deferred();

  setTimeout(
    function resolveOperator() {
      deferred.resolve(shieldAndWheels + ", Colored in red");
    }, 2000);

  return deferred;

}

This code is self explanatory but let’s review it quickly:

At the beginning we define the method chain, each method in the chain is actually a vendor method wrapped in $q.when.
As you can see, carShieldFromMechanic and wheelsFromVendor returning simple values while wheelsFromVendor returns jQuery promise, and all of them wrapped by $q.when.
Each chained method receives a data from the previous method in the chain, and finally we are .catching to see if any of the methods didn’t retrieve a value or an error occurred in one of them.

You can play around and try to change

deferred.resolve(shieldAndWheels + ", Colored in red");

to

deferred.reject("error");

or throw an error inside on of the other methods to see how .catch will handle this error.

And that’s it, now you have a complete working flow which combining multiple 3rd party libraries and perfectly integrated into your Angular application.

AngularJs, Grunt, Optimizations, Performance

Improving performance in production environment


By default, when we create data-bound elements, angular attaches additional information about the scope and the bindings to the DOM node, and then applying ng-binding CSS class to the data bound element. Debuggers (such as Batarang) and test frameworks (Like Protractor) requires this information to be able to run.

Let’s try it out by ourselves

We will setup a simple app with a controller and a directive with isolated scope.

HTML

<div ng-controller="myController">controller</div>
<isolated-scope data-binding="isolated scope"></isolated-scope>

JavaScript

app.directive('isolatedScope', function() {
  return {
   scope: {
     binding: "@binding"
   },
   template: "{{binding}}"
  };
});

app.controller('myController', function($scope) {
  $scope.location = "You are in a controller";
});

Next, if we’ll execute in the console:

angular.element(document.querySelector('div')).scope();

We will get the scope of our controller.

$ChildScope: null
$$childHead: null
$$childTail: null
$$listenerCount: Object
$$listeners: Object
$$nextSibling: Scope
$$prevSibling: null
$$watchers: null
$id: 2
$parent: Scope
location: "You are in a controller"

And if we try –

angular.element(document.querySelector('isolated-scope')).isolateScope();

We will get the isolated scope of the directive

$$childHead: null
$$childTail: null
$$destroyed: false
$$isolateBindings: Object
$$listenerCount: Object
$$listeners: Object
$$nextSibling: null
$$phase: null
$$prevSibling: ChildScope
$$watchers: Array[1]
$id: 3
$parent: Scope
$root: Scope
binding: "isolated scope"


OK, that’s informative. So what’s the problem?

The problem is, that according to Angular’s running in production document, this info may come at a cost of “significant” performance loss.

Luckily, the solution is quite simple. Since you need this information while developing and debugging, but you do want to turn it off in production,
you can easily switch it on/off in the config phase of the application, and control this configuration with your build tool. Let’s see an example –

First, we configure debugInfoEnabled during the config phase of our application.

// application's config constant
angular.module('myApp').constant('myConfig', {
	enableAngularDebugInfo: true
});

// setup necessary changes in config phase 
angular.module('myApp').config(function ($urlRouterProvider, myConfig) { 
  $compileProvider.debugInfoEnabled(myConfig.enableAngularDebugInfo);
});

The value enableAngularDebugInfo should be true by default, since we need it for development.
Next, we should disable it when building the application for production. I will demonstrate an example with Grunt, but you can do it with Gulp, Cake, Broccoli or any other task runner.

Configuring GruntFile to disable debugInfoEnabled in production

For simplicity purposes, i have removed from the GruntFile all commands that don’t directly relevant to disabling AngularDebugInfo:

module.exports = function (grunt) {

    // Project configuration.
    grunt.initConfig({
        'string-replace': {
            disableAngularDebugInfo: {
                options: {
                    replacements: [{
                        pattern: 'enableAngularDebugInfo: true,',
                        replacement: 'enableAngularDebugInfo: false,'
                    }
                    ]
                },
                src: 'temp/app.full.js',
                dest: 'temp/app.full.js'
            }
        }
    });

    // for build task, run string-replace.
    grunt.registerTask('build', ['string-replace']);
};

As you can see, we used the neat grunt-string-replace to replace true to false when running the build command. Obviously the actual build command will contain many more tasks (tests, jshint etc’), string-replace it’s only one of them.

And that’s it, now in your app.full.js file, angularDebugInfo will be disabled, so you can keep on developing while boosting up your applications performance in production environment.

AngularJs, Javascript, Optimizations, Performance

Shorten $digest cycles with one time bindings


In large scale angular apps (or poorly designed small-medium scale), performance issues, if not caught on time, could be extremely painful to fix. Memory leaks, uncontrolled watchers, unnecessary expressions processed during the $digest cycle and the list goes on and on.

Today I wanted to share a little addition presented in angular 1.3 and allows us to shorten our $digest cycles.

Consider the following (simple) example:

Controller


myController.controller('MyController', function($scope, urlConfigurations, $timeout) {
    var vm = this;
    vm.userId = 'firstUser';
    vm.facebookProfile = urlConfigurations.facebook;
    vm.twitterProfile = urlConfigurations.twitter;
    vm.linkedin = urlConfigurations.linkedin;

    vm.nextUser = function() {
        vm.userId = 'secondUser';
    };
});

Constant

myApp.constant('urlConfigurations', {
    	facebook: 'http://facebook.com/?profile=',
        twitter: 'http://www.twitter.com/?id=',
        linkedin: 'http://www.linkedin.com/?id='
});

View

<div ng-controller="MyController as vm">
      <a ng-href="{{vm.facebookProfile + vm.userId}}">Facebook</a>
      <a ng-href="{{vm.twitterProfile + vm.userId }}">Twitter</a>
      <a ng-href="{{vm.linkedin + vm.userId}}">Linkedin</a>
      
      <button ng-click="vm.nextUser();">Next User</button>
</div>

Looks legitimate piece of code, right? We have urlConfigurations constant which holds our URLs, then we retrieve it in our controller and sending it to the view , which combining it with vm.userId to create links to social media account of the specific user id. The nextUser() method allows us to change the user id, which will also modify the social media URLs.

Where is the problem?

The problem is that we have 3 unnecessary watchers here: vm.facebookProfile, vm.twitterProfile and vm.linkedin. So, when we will update vm.userId, it will trigger a $digest cycle that will process everything on the scope, including those 3 watchers that will never change in runtime, making processing them redundant and time/resources consuming. Now consider a case where we don’t have only 3, maybe we have a 100 (a good example might be localization implementation).

The solution

As for angular 1.3 > , the solution is quite simple. We can just add :: near the property we want to bind only once. So in our view, we will be using:

<a ng-href="{{::vm.facebookProfile}}{{vm.userId}}">Facebook</a>
<a ng-href="{{::vm.twitterProfile}}{{vm.userId}}">Twitter</a>
<a ng-href="{{::vm.linkedin}}{{vm.userId}}">Linkedin</a>

In this case, vm.facebookProfile, vm.twitterProfile and vm.linkedin won’t be processed in the $digest cycle each time vm.userId is modified.

AngularJs, Javascript

Extending underscore.js with your own methods


Every project have its own common/utilities library, many projects also use underscore.js (or even ports of this library such as underscore-java or underscore-php). You can easily integrate your own utilities functions into underscore to make thing cleaner and reduce the amount of requires (or global objects, depending where you’re holding your utilities).

In order to extend underscore with your own method you can use _.mixin .

_.mixin({
    excerpt: function(string, numOfChars) {
        return string.substr(0,numOfChars);
    }
});

Then you can easily do:

var string = _.excerpt(‘Give me first 4 chars’,4); // string = ‘Give’

That’s it.

AngularJs, Javascript

Using decorators to replace and tweak 3rd party services for your specific needs


What are decorators?

Decorators allows us to enrich, or replace certain part of module we are not allowed (or shouldn’t) touch it’s source code. For example: 3rd party libraries, modules that we are not maintaining and the list can go on.

Real-life scenario

Let’s say we have file upload functionality in our application, and for that, we are using a great module we found ngmodules.org. For the sake of the example, let’s work with ng-file-upload.
So, we are extremely satisfied with this module, but then one bright day the requirements of the file upload changed. From now on, we need to upload those files to a remote machine, using special access credentials.

So what will we do? Should we replace the ng-file module? We can’t, we’re using it’s other nice features like drag and drop, image resize, shims for older IE’s and what not.
Then should we rewrite the upload method of the module? We don’t want to go down that rabbit hole. We should avoid modifying vendor libraries as much as possible.

Decorate it

Then our best option is to decorate the service, by adding/replacing methods during our module’s config phase.

Here is a simple upload example provided by the creator of ng-file-upload on its GitHub page.

View

<body ng-app="fileUpload" ng-controller="MyCtrl">
  <form name="myForm">

    <fieldset>

      <legend>Upload on form submit</legend>

      Username:
      <input type="text" name="userName" ng-model="username" size="31" required>

      <i ng-show="myForm.userName.$error.required">*required</i>

      <br>Photo:
      <input type="file" ngf-select ng-model="picFile" name="file"    
             accept="image/*" ngf-max-size="2MB" required>

      <i ng-show="myForm.file.$error.required">*required</i><br>

      <i ng-show="myForm.file.$error.maxSize">File too large 
          {{picFile.size / 1000000|number:1}}MB: max 2M</i>

      <img ng-show="myForm.file.$valid" ngf-thumbnail="picFile" class="thumb"> <button ng-click="picFile = null" ng-show="picFile">Remove</button>
      <br>

      <button ng-disabled="!myForm.$valid" 
              ng-click="uploadPic(picFile)">Submit</button>

      <span class="progress" ng-show="picFile.progress >= 0">
        <div style="width:{{picFile.progress}}%" 
            ng-bind="picFile.progress + '%'"></div>
      </span>

      <span ng-show="picFile.result">Upload Successful</span>
      <span class="err" ng-show="errorMsg">{{errorMsg}}</span>

    </fieldset>
    <br>
  </form>
</body>

Controller

//inject angular file upload directives and services.
var app = angular.module('fileUpload', ['ngFileUpload']);

app.controller('MyCtrl', ['$scope', 'Upload', '$timeout', function ($scope, Upload, $timeout) {

    $scope.uploadPic = function(file) {
    file.upload = Upload.upload({
      url: 'https://angular-file-upload-cors-srv.appspot.com/upload',
      data: {file: file, username: $scope.username},
    });

    file.upload.then(function (response) {
      $timeout(function () {
        file.result = response.data;
      });
    }, function (response) {

      if (response.status &amp;amp;gt; 0)
        $scope.errorMsg = response.status + ': ' + response.data;
    }, function (evt) {
      // Math.min is to fix IE which reports 200% sometimes
      file.progress = Math.min(100, parseInt(100.0 * evt.loaded / evt.total));

    });
    }
}]);

Replacing the upload method without touching vendors code

For the sake of the example, let’s say we’ve used his example as is. We also used the drag and drop, image resize and shim functionality.
But now we need to replace only the upload method without touching any code of the library.

Step 1 – Replacing the upload method of the service in our module’s config phase

app.config(function($provide) {
    $provide.decorator('Upload', function($delegate, $q) {

        $delegate.upload = function(url, data) {

            var deferred = $q.defer();

            console.log('We have replaced the original upload method');

            deferred.resolve();

            // no error handling for the sake of simplicity

            return deferred.promise;
        }

        return $delegate;
    });
});

Step 2 – Replace the .upload usage in our controller to play nicely with our new upload method

file.upload = Upload.upload({
      url: 'https://angular-file-upload-cors-srv.appspot.com/upload',
      data: {file: file, username: $scope.username},
    }).then(function(result) {

        $scope.picFile.result = true;

    });

As you can see, in the config phase of our module, we used $provide to decorate our Upload service.
We have used $delegate (which is the original service instance) and replaced its upload method to a method that suits our needs.
Then we adjusted our controller to play nicely with our new .upload method, and that’s it.

In some cases, when we can make the replaced method to return the same data to success/errors, we don’t even have to touch our controllers.
So from a possibly costly change in the application, we can get away with decorating one single method.