Tuesday, 11 June 2013

Yeoman + Express + Angular = Full-Stack Workflow

Yeoman is one amazing toolkit that makes kick-start and application development management workflow a breeze. It integrates a "preview" server based on Connect middleware but primarily concentrates on "client-side" workflow. While there is some experimental support for Express and Yeoman guys have integration with various back-ends on their roadmap, I needed a full-stack workflow solution right away that will not only serve my "SPA" client application but also be the "API" server. So, after tinkering for a couple of hours, here I'm, blogging about it :).

The process is quite simple and involves generating an application using Yeoman Angular generator in the usual manner and then a little modification of Gruntfile.js. Here are the steps -

  1. Create an Angular application using Yeoman Angular generator in usual way.
  2. Install express, grunt-contrib-watch and grunt-express-server using npm install and use the save flags as shown below so that the package.json file is updated automatically.
    npm install express --save
    npm install grunt-contrib-watch --save-dev
    npm install grunt-express-server --save-dev
    
  3. Uninstall grunt-contrib-livereload, grunt-regarde and grunt-contrib-connect using npm uninstall. These are not needed anymore and the plugins installed in previous step will provide the necessary functionality.
    npm uninstall grunt-contrib-livereload --save-dev
    npm uninstall grunt-regarde --save-dev
    npm uninstall grunt-contrib-connect --save-dev
    
  4. Now comes the modification of Gruntfile.js file. You'll need to remove configuration related to the plugins mentioned in the previous step and add configuration for plugins added in step 1. You can find the exact changes in the embedded gist by doing a diff between revisions.
  5. Add an Express server at the root of the directory. You can take server.js from the gist and build upon it.
That's it. We now have a full-stack setup with all the Yeoman goodness fully preserved.

Here a few points worth noting -

  • Gruntfile.js Line 20 - Note there are only dev and prod express servers configured. The original configuration had a connect-based test server too. But Karma doesn't need a server for running Angular unit as well as e2e tests. So I think even the original configuration is redundant.
  • Gruntfile.js Line 54, 55 - I have added server.js file and server directory that will hold the server code in the app root directory. These have been added to watch configuration so that if server code is updated, application is reloaded and changes are reflected immediately.
  • Gruntfile.js Line 271 - Express dev server has been added to the grunt server task.
  • server.js Line 22 and 24 - The Express server serves the "client" files from app directory in dev mode and from dist directory in production mode, thereby providing nice integration with Yeoman build cycle.
  • Live reloading of HTML in the browser - I tried client as well as server approach mentioned in the grunt-contrib-watch documentation to enable live reloading of HTML but nothing worked. So, finally I installed Chrome extension mentioned on the same page and it's working beautifully. With the watch configuration mentioned in earlier point, any code change, be it a server-side or client-side, is immediately reflected and browser is automatically refreshed making development experience a pleasure.

There you have it. A full stack Yeoman workflow with Express and livereloading.

Here is the gist. Feel free to use the code in any manner you want.

Saturday, 20 April 2013

Using AngularJS Decorators

Ever wondered about intercepting an Angular service creation to add behavior to the service instance that is being returned or replace it with something else altogether? Well, you don't have to do anything fancy for that, this mechanism is built right into Angular :). The $provide service, along with other types of providers such as factory, service, value etc, supports decorators too. While you can find decorator usage in angular-mocks.js, examples are a bit difficult to find in general. Hence this post :).

Let's consider a contrived scenario. HTML5 brings FileSystem API to browser, but support for it in browsers varies. I'm on latest Chrome (Chrome 26) and it supports it but none of the other browsers do. Let's say we need a simple data storage functionality in our Angular application which stores data in file system if it's available or in sessionStorage if it's not.

Here is the full working plunk that demonstrates decorator usage.


You'll find two providers registered in above example -

  1. storageServiceFile - Stores data in File System
  2. storageService - Stores data in sessionStorage
Now comes the decorator part. Here is how it looks like -
app.config(function($provide) {
  $provide.decorator('storageService', 
   ['$delegate', '$injector', '$rootScope', 'fileSystem', 
  function ($delegate, $injector, $rootScope, fileSystem) {
      if (fileSystem.requestFileSystem) {
        $rootScope.isFileSystemSupported = true;
        return $injector.get('storageServiceFile');
      } else {
       $rootScope.isFileSystemSupported = false;
       return $delegate;
      }
   }]);
});
...
...
...
app.controller('MainCtrl', ['$scope', 'storageService', function($scope, storageService) {
...
...
Points worth noting are -
  • In the config callback function, $provide service has been injected and a decorator is registered.
  • A decorator is just like any other provider. You can inject whatever than can be injected into a provider including user-defined services. In the example above, fileSystem is a user-defined service that has been injected into the decorator.
  • The $delegate argument to the decorator function is the actual service instance which it can choose to return as is, monkey-patch or replace altogether.
  • In the example above, the decorator returns instance of storageServiceFile service if FileSystem is supported by the browser else returns the original storageService instance which stores data in sessionStorage.
  • At runtime, the decorator comes into picture when Angular instantiates MainCtrl, finds out it has dependency on storageService, instantiates it and finds there is a decorator for this service and invokes it before the service instance is handed to the controller.

If you play with the plunk in latest Chrome, you can see data being stored in file system and for Firefox and others, in sessionStorage.

Sunday, 17 February 2013

Controller Inheritance in AngularJS

I was looking for abstracting common functionality into base controllers to make them reusable. I took a look at typical JavaScript Inheritance patterns and particularly liked Functional Mixins approach outlined in this article. I followed along and no surprises - everything worked fine. Only one small thing bothered me - dependency injection. A base controller might need a different set of dependencies and there was no clean way of separating dependencies for base and child controllers.

That's when I stumbled upon this gem by Misko on the Angular mailing list. The Angular $injector.invoke function mentioned in this thread does inheritance in usual JavaScript way with the addition of proper dependency injection.

Here a small plnkr to show it in action -


ParentCtrl is a typical Angular controller function but you'll notice that it's not registered as a controller. It depends on $location service while the ChildCtrl does not. ChildCtrl gets hold of injector and calls invoke on it passing the "parent" reference (ParentCtrl in this case) and its own reference as second argument. The invoke function does the magic of "mixing-in" the parent behavior into the child.

I have found this technique incredibly clean and useful so far. It helps making controllers DRYer and reusable. Hope this helps you too.

Tuesday, 1 January 2013

Addon functionality for built-in directives in Angular

In Angular, not only you can create your own directives but also redefine built-in directives to add additional functionality to them. This technique can come in handy in many situations.

Let's see this in action with the built-in form directive. We would like our form, in addition to the standard Angular form directive functionality, to notify its ancestors when it becomes dirty and make itself pristine again when ancestor notifies it to do so.

Here is the fiddle for it.


The markup is usual. There is a div with controller "controller" attached to it and it wraps the form 'myForm' thus becoming ancestor of it. The interesting part is re-declaration of form directive.

myApp.directive('form', [function () {
    return {
        restrict: 'E',
        require: 'form',
        link: function (scope, element, attrs, ctrl) {
            scope.$watch(attrs.name + '.$dirty', 
                function (newValue, oldValue) {
                    if (newValue != oldValue && newValue === true) {
                        scope.$emit('formDirty', attrs.name);
                    } 
                });
            scope.$on('formClean', function () {
                ctrl.$setPristine();             
            });
        }
    };
}]);

Note that we mention 'form' as require value so that Angular FormController associated with the form 'myForm' is made available to our directive. In the link function, a watch is put on form $dirty and an event 'formDirty' is emitted in such case. Also, a listener is added for 'formClean' event that sets the form back to pristine state using FormController.

The controller associated with the wrapper div listens to 'formDirty' event and shows a message on the page when it receives one and it broadcasts 'formClean' event to its descendants when user resets the form using reset button.

Note the ng-disabled attribute has been added to reset button just to show that the all the built-in form directive functionality is available for use.

Note: The $setPristine() API is available only from Angular 1.1.x release.

Tuesday, 4 December 2012

AngularJS bits - Modular Controllers

Controllers are basic building blocks of an AngularJS application and you can't get by without writing a few. These are pure JS functions and you can create them as global functions as shown in most of the tutorials.

But, and that's a very big but, polluting global namespace like this is never a good idea in a JS app. AngularJS, being as good as it is, provides an excellent way to create controllers in a modular way using API that is similar to the one we use to create directives, services and filters.

Please take a look at the fiddle below. The idea is using module.controller to define a controller and using the controller "name" string expression everywhere as shown in the fiddle. And that's it. As simple as that :).


Saturday, 17 November 2012

Transclude in AngularJS

Transclude - That's not a word you'll find in a dictionary :). Once you dive into Angular, creating custom directives is a daily chore and having good understanding of transclusion becomes imperative. To explain it in one sentence, transclusion consists of plucking out the content of a custom directive, processing it against right scope and then placing it at a marked position in the template of that directive. While the basic transclude using the built-in ngTransclude directive is easy enough, there isn't much clarity in some areas in terms of documentation or examples. These areas are -

  • Purpose and usage of transclude argument that a directive compile function receives.
  • Purpose and usage of $transclude injectable in a Controller.
  • Isolate scope and transclude.
  • Transcluding into an attribute.

I'll try to throw some light on these with the help of working fiddles.

Basic transclude

Let's start with the most basic transclude example. Let's say, we are creating a buttonBar directive that a user can use to add a group of buttons to a page. The directive takes care of alignment of the buttons. Just to note, I have used Twitter Bootstrap as CSS framework.

Here is the fiddle for it.


Take a look at the markup. The buttonBar directive wraps a couple of button elements. The button elements also have a class-based directive "primary" attached to them. Don't worry about it though, it simply attaches appropriate Twitter Bootstrap classes to them. The directive provides transclude: true attribute and it's template uses ng-transclude directive on a contained div. At run-time, Angular gets the content of the custom directive, processes it and sticks the resultant markup in the ng-transclude div in the template. And that's all there to it. Quite simple, isn't it?

Transclude at multiple locations

Lets say we would like to enhance our buttonBar directive to have two kinds of buttons - primary and secondary; with primary buttons right-aligned and secondary left-aligned. It would entail picking up the contents(buttons in our example) of the directive and adding them into two separate divs, one for primary buttons and the other for secondary buttons. Transclude into two different locations, if you will. The result should look something like this -

Well, that's not possible with the default mechanism. One approach to achieve this could be -

  1. Allowing the default transclude in an element in the template.
  2. Programmatically moving child elements(buttons) to appropriate div.
  3. Finally, removing the original transcluded element from DOM in compile or link function of the directive.

Here is a fiddle that demonstrates this approach.


While this approach gives us the intended result, allowing default transclude to happen in an element and then removing it from DOM manually is not really efficient. That's where the transclude argument to compile function and $transclude injectable into Controller come into picture.

Transclude argument to compile function in a directive

The Angular developer guide for directive gives following signature for the compile function of a directive -

function compile(tElement, tAttrs, transclude) { ... }

And here is what it says about the third argument -

transclude - A transclude linking function: function(scope, cloneLinkingFn).

Alright, let's use this function to achieve what we achieved in the last example without the need to transclude into an element and then removing it from DOM.

Here is the fiddle for it.


Please note there is no scope available in compile function and you'll have to pass the element that compile function received as the first argument to the transclude function. You might want to use this approach if you are already using the compile function (which is quite rare, at least for me) and don't need to work with scope. Otherwise, the next approach of injecting $transclude into Controller is the best bet.

Injecting $transclude in a Controller

The Angular developer guide for directive states the following for $transclude injectable for Controller -

$transclude - A transclude linking function pre-bound to the correct transclusion scope: function(cloneLinkingFn).

And here is how we can use it for our buttonBar directive.



Transclude and scope

The Angular developer guide for directive mentions that a directive isolated scope and transclude scope are siblings. Now, what does that mean? If you take a careful look at previous example, you'll notice that parentController creates a scope, the buttonBar directive declares an isolated scope under it and as mentioned in the Angular documentation, transclude creates yet another scope. I have added log statements at appropriate places in the directive to illustrate the relationship between these three scopes. Here is how the output looks like -


You can clearly see the directive isolate scope and transclude scopes are siblings.

Transcluding into an attribute

Well, you can't really do that but achieve something to that effect using the following trick mentioned on stackoverflow.

That covers all I wanted to regarding transclude in AngularJS. Hope this post proves useful to you. Happy ng-ing :).

Update (20th Feb 2013) - scope and transclude argument to compile function

The lack of scope in compile function and the signature of transclude argument to compile function that mentions scope as its first argument leaves a lot of "scope" for confusion :). One thing is certain, there is no scope in compile function. Here it is straight from horse's mouth - https://groups.google.com/d/msg/angular/QbZt4kw5cTY/h-ZIgPO0wrsJ.

So what's the first argument actually? It turns out it's just the jQuery-wrapped root element of the template for the buttonBar directive. This is how it looks like during debugging -

.

Note the absence of scope related behavior such as $$watchers or $$listeners on it.

Here is updated version of third fiddle from top with development version of AngularJS instead of minified version. You can put a debug point as shown in the snapshot above and see for yourself. Hope this clarifies it further.

Update (16th March 2013) - All fiddles updated to latest AngularJS release - 1.1.3

In contrast to what I have mentioned in the earlier update and behavior in earlier releases, the transcludeFn passed to compile function now indeed expects scope as first argument in latest AngularJS release (1.0.5/1.1.3). Therefore the call to this function needs to be made from link function that is returned from compile function as it has access to scope. The fiddle for section Transclude argument to compile function in a directive as been modified accordingly.

Sunday, 4 November 2012

Selecting a JavaScript Web Framework

My team is currently in process of re-writing our (huge) web application to follow SPA architectural approach. When I say our web application, it's actually a framework/platform on which our clients build their applications. In this regard, at around April/May this year, I got an opportunity to evaluate various JavaScript frameworks/libraries and be part of decision making to select the apt one for our requirements. While the elaborate details of requirements, selection process and evaluation matrix reside on our internal wiki, I would like share my impressions about the frameworks we evaluated.

Selection Criteria

Here is the general list of requirements (in no particular order) that we considered for evaluating the frameworks -

  • Separation of concerns between components (MVC/MVVM/MV - whatever)
  • Ease of use - learning curve and productive development
  • Data Binding ability
  • Modularity - logical code organization
  • Templating and possibility of fetching them on-demand remotely
  • Ability to play nicely with other libraries (mainly jQuery)
  • Extensibility (ease of adding custom functionality)
  • Reusable components - Capability to create reusable components
  • Routing/Bookmarkability
  • Testability
  • Maturity and size of the community

Candidates

After initial research and PoCs, we shortlisted the following frameworks/libraries -

  1. backbone.js
  2. KnockoutJS
  3. ember.js
  4. batman.js
  5. AngularJS

My Impressions

  1. backbone.js

    Backbone.js is a well-established and well-respected library in the JS community. It's very easy to learn and plays nicely with jQuery. It doesn't provide bindings functionality out of the box. It's minimal by design and is a library, not a framework. Depending upon one's perspective, this can be viewed as a pro or a con. On one hand, it gives you absolute freedom and control to structure your application the way you want. On the other, it might be viewed as too "bare bones" and might result in having to write quite some "boilerplate" code to make things work together.

    For us, it was more of the latter and therefore we had to let it go reluctantly.

  2. KnockoutJS

    This, in my opinion, is one of the best libraries available in the JS webapps frameworks/libraries world at the moment.

    • Almost no learning curve. Super-easy to learn and use. Amazing documentation, live examples and tutorials, I would say right amongst the best in opensource projects.
    • Does bi-directional data binding in declarative manner. You need to use KO api such as ko.observable and ko.computed to setup observables in your ViewModel.
    • Plays nicely with jQuery.
    • Has DOM-based templating which, in my opinion, is the right approach for templating.
    • Provides custom bindings and custom functions as means of extensibility and creating custom components.
    • Mature library with number of releases under it's belt and active community behind it.
    • It's a library absolutely focused around View Models and bindings. Doesn't offer much for separation of concerns.
    • Doesn't have any opinions on the logical code organization. This responsibility is left to the developers.
    • Doesn't provide routing/bookmarkability out of the box. You have to choose and integrate third-party library such as Sammy.js for this purpose.

    Based on our PoCs, KnockoutJS turned out to be our second most favourite library.

  3. ember.js

    I have mixed feelings about ember. We had high expectations due to the SproutCore legacy and wanted to like it but were let down due severe lack of documentation and examples. (This situation might have changed for better in last six months.) Also, it was quite in flux back then and there was a lot of confusion about readiness and state of migration (from SproutCore to Ember) for plugins such as StateManager and ember-data. Absence of mailing list didn't help either. On the templating front, while I'm aware that a lot of people really like handlebars.js, I tend to differ. DOM-based templating looks a lot cleaner solution to me and it also preserves the IDE (or a nice text editor such as Sublime Text 2, which arguably is the best editor around these days) benefits such as syntax highlighting and code completion. A bunch of handlebars templates wrapped in script tags in an HTML file simply doesn't offer that luxury. Probably a minor point but still important when dealing with large applications.

    We still took it to the final showdown but couldn't complete the spike in the allotted time frame owing to the factors mentioned above and hence dropped it from our consideration.

  4. batman.js

    Batman.js is quite an impressive looking new framework. It takes inspiration from RoR and strives to be "Rails" of the JS webapp frameworks world with pre-defined directory structure, generators, test server and even a optimized NodeJS based server in the making.

    • Batman provides clean separation of concerns on the MVC lines. While the model and controllers extend from framework classes, Batman.Model and Batman.Controller, the views are pure HTML with declarative data-* bindings.
    • Batman Model provides a very rich API very similar to Rails ActiveRecord with functionality such as validations and CRUD being inherited by model subclasses.
    • The StorageAdapter approach is a very clever approach for model persistence with strategies like Batman.LocalStorage and Batman.RestStorage available out of the box.
    • The controllers are singleton and that is something that struck me as odd. It's sort of throwback to Struts days :).
    • The routing is provided out of the box.
    • It plays nicely with jQuery.

    While BatmanJS is very promising and offers so many nice features, there are a couple things worth mentioning. CoffeeScript is the language of choice for BatmanJS developers. You can use JavaScript of course, but whatever documentation or help available is in CoffeeScript. While personally I quite like the Ruby syntax, our's happens to be primarily a Java shop and Ruby syntax is alien to most of the developers. CoffeeScript also doesn't obviate the need to learn JavaScript since all the debugging still needs to be done in JavaScript anyway. So, to start development, my Java team will need to first pickup JavaScript and then CoffeeScript, which in my mind, is one step too many to be productive. The second thing is it's quite a young project and as it tends to happen with so many young projects, documentation is quite lacking. On account of these two factors, we didn't consider it any further.

  5. AngularJS
  6. That brings us to the last framework in our list. I had an eye on AngularJS even before it got the "by Google" tag that now adorns its web site and clearly remember not liking the "ng" xml namespace approach. But amends happened in the nick of time for us :).

    • AngularJS provides a clean separation of concerns on MVC lines. The most remarkable thing about scopes (which roughly correspond to model) and controllers is that they are pure JS functions. Unlike ember, knockout and batman, you don't need to extend from any framework specific extension points. AngularJS views are pure HTML with custom data-* attributes that provide two way bindings.
    • It provides excellent means of logical code organization in the form of modules. It provides way to abstract shared functionality and data into services. It brings the the Dependency Injection paradigm to JS.
    • It has a moderate learning curve since it defines quite a few abstractions of its own. But once you wrap your head around them, you realize it's all very logical. Though it's also quite a young project, the documentation is excellent and the mailing list is very active.
    • Angular templates are DOM-based and you can have partials - templates divided into manageable chunks specific to single functionality and loaded on demand.
    • Angular Directives is an amazing way of creating new components, composing them to create composite components and wrapping third-party widgets and exposing them as Angular components.
    • Provides nice AJAX abstraction in form of $http service and $resource service built on top of it that provides means to interact with RESTful server-side data sources.
    • Angular plays nicely with jQuery. If you load jQuery before Angular, it uses that by default for DOM manipulation tasks.
    • It has an excellent routing support in form of $routeProvider service. You can also define routes dynamically, for example, getting JSON response from REST service and define routes based on it.
    • Testing has always been a challenging concern in UI development. But due to excellent logical code organization features like modules and services, controllers and scopes being pure JS functions and dependency injection, unit testing is one area where Angular really shines.

    AngularJS very quickly became our favourite framework in our PoCs.

Conclusion

We selected KnockoutJS and AngularJS for our final showdown. We did spikes in both to implement similar functionality and arrive at result -

and the framework we selected is - AngularJS.

We have been developing in AngularJS since. The results have been outstanding and we are very happy with our choice. Great work AngularJS guys, cheers to you for creating such an amazing framework. Thank you and keep up the wonderful work :).