AngularJS for jQuery Developers

Posted by | Development | 34 Replies.

AngularJS-large

AngularJS is a sweet web app framework. It comes with decent official documentation and samples, it looks superior among a large number of frameworks in an almost-real-world application test (the famous TodoMVC project), and there are cool presentations and screencasts about it all over the web.

But for a developer who has not used frameworks similar to Angular before, and has mostly worked with JavaScript libraries like jQuery, there may be some difficulty in shifting from the jQuery mindset to the Angular mindset. At least there was for me, and I’d like to share some notes–maybe this will be useful to someone.

Not a Library

The first thing to understand about AngularJS is that it’s fundamentally a different kind of tool. jQuery is a library. AngularJS is a framework. With libraries, your code decides when to call a particular function from a library. With frameworks, you implement callbacks, and the framework calls you when it decides to.

The difference is easy to understand when you think about what happens at runtime. What is jQuery doing at runtime? Mostly, nothing. Any execution of code within jQuery happens in response to your code triggering some jQuery function, prompted by some DOM event.

At loading time, Angular turns your DOM tree and javascript into an angular app. The HTML with Angular directives and filters is compiled into a tree of views, the corresponding scopes and controllers get attached to them, and internal application loop ensures data binding between the view and the model. This is real MVC stuff, with very clean separation between view, controller and model. You can think of the main event/rendering/binding loop as of one that’s running all the time, calling your controller core as needed.Angular MVC

Every time Model is updated – either through an asynchronous AJAX call, or through direct manipulation somewhere in controller code, Angular re-runs its $digest loop, updating the data bindings and keeping everything in sync.

Declarative, rather than Imperative

Unlike some other libraries and frameworks, Angular does not treat HTML or JavaScript as a bug that needs to be fixed (I’m looking at you.) Instead, it augments it in such a natural way that you can’t believe you did not think of it yourself. This is easier to show than to explain.

Let’s say we want to show/hide an element based on a checkbox state. In jQuery, we would do something like this:

<input id="toggleShowHide" type="checkbox"><div id=”specialParagraph”>
    This content will disappear and reappear if you click the checkbox above
</div><script>
    $(function() {
         function toggle() {
            var isChecked = $('#toggleShowHide').is(':checked');
            var specialParagraph = $('#specialParagraph');
            if (isChecked) {
                specialParagraph.show();
            } else {
                specialParagraph.hide();
            }
        }
        $('#toggleShowHide').change(function() {
            toggle();
        });
        toggle();
    });
</script>

Notice that the JavaScript code treats DOM in an imperative manner: take this node and that attribute, look at its value, do this or that.

Now let’s see the same in Angular terms:

<input ng-model="showSpecial" type="checkbox">
<div ng-show=”showSpecial”>
    This content will disappear and reappear if you click the checkbox above
</div>

This is it! No code at all, just a very clear declarative way of specifying bindings and rules. Here’s a live version you can play with: http://jsfiddle.net/Y2M3r/

Direct manipulation of the DOM is not only unnecessary, it is discouraged in the Angular approach. The DOM should be specified in views, data in scopes, functionality in controller, any non-trivial transformations in custom filters and directives.

This clean separation of concerns seems like a lot to digest at first, but when the project gets large, it pays off tremendously: the code is easy to maintain, easy to separate into modules, convenient to test and diagnose.

Two-way Data Binding

Binding a DOM value to a model in a controller scope makes it truly linked to the scope variable. You probably know this from the docs and demos, but I just can’t help mentioning it. It’s one of the huge “wow” moments in the first impressions you get from Angular.

<input type="text" ng-model="yourName" placeholder="Enter a name here" />
<h1>Hello {{yourName}}!</h1>

Live version: http://jsfiddle.net/6UnVA/1/

Dependency Injection

Forgive me for sounding opinionated, but Angular has the most elegant way to handle dependencies in the world.

Say, you have a JSON data source wrapped into a $resource on Angular side:

DataSource = $resource(url, default_params, method_details)

– see documentation for details. Any controller that needs to use this JSON data, can do so by including DataSource as one of the controller parameters. That’s all that is needed. This is a single piece of magic that continues to amaze me every day I work with AngularJS. You need to make an asynchronous HTTP request in your controller? Include $http in the parameters. Need to log to console? Include $log as your controller function argument.

What happens internally is this: Angular analyzes your function’s source code, finds the arguments, and infers from them the services your code requires.

Data Access

While Angular gives you complete freedom on how to structure your Model layer  (you can use plain data variables, objects, and arrays in any combination),  it provides a convenient way to talk to a REST API on the server. For example, here’s a way we might define and use the set of calls to retrieve and save User records.

var User = $resource('/user/:userId', {userId:'@id'});
var user = User.get({userId:123}, function() {
  user.abc = true;
  user.$save();
});

Angular predefines reasonable defaults for getting, setting, deleting, and querying records. And parametrized URLs give you the ability to customize data access to your needs.

Other things that deserve to be mentioned but weren’t are form validation, unit testing, and angular-ui library. Perhaps in a future post.

See also: I’ve Been Doing It Wrong!

 

(Image from http://angularjs.org/)