English |  Español |  Français |  Italiano |  Português |  Русский |  Shqip

Choosing a JavaScript Framework

Frameworks: AngularJS

AngularJS

Background

Basic Facts
Released: 2009 (1.0 in 2013)
Stars on GitHub: 20k+
Dependencies: None, loads its own smaller jQuery library
License: MIT License

At the time of this writing, AngularJS is the fastest-growing JavaScript framework in the field. Popularized by Google, it had massive growth in 2013. Angular was originally written by Misko Hevery and Adam Abrons. Hevery continued on the project on the project while working at Google and more developers at Google joining the project over time. It has 600+ contributors (Igor Minar becoming a major contributor) and released its 1.0 version in 2013.

AngularJS developed from the idea that JavaScript applications should not be written in the same way as server-side applications. The creators of Angular believed that client-side code at its core should be more declarative (like CSS and HTML). It can be summed in their own words with “Angular is what HTML would have been had it been designed for applications.”

Minar declared Angular to be a “Model-View-Whatever” (MVW) framework in 2012, in response to arguments over whether the app was following an MVC (controller) or MVVM (view model) paradigm. Angular has controllers, but the way it uses directives to bind views to data is very much like a view model. Let’s take a look at directives.

When you hear about Angular, one of the first things you'll hear about is “directives”. A directive allows you to modify the behavior of an element in the DOM, or even write your own new elements. To understand how Angular re-thinks HTML, it helps to see it in action. A fun sample of this is writing a unicorn directive.

 

angular.module('myapp', [])

    .directive('unicorn', function() {

        return {

            restrict: 'E',

            link: function(scope, element, attrs) {

                element.html('Unicorn')

            }

        };

    });

Now, assuming I have an element in the context of ng-app= "myapp", I can have < unicorn></unicorn > to display the text “unicorn.” It’s a silly example, but you get the idea.

There’s a much cooler example of the unicorn directive written by Brian Ford (his example draws a unicorn on a canvas element), available on GitHub and the Bower package manager, should you need unicorns as a feature in your app.

Strengths and weaknesses

Angular’s major strengths are its small setup and its great list of features. You’ll see in the sample app how little code we can get running for an app. It’s definitely not quick or easy to get started with Angular (there’s a lot of documentation to read), but it doesn’t take much code to get interaction happening.

A stand out feature that sets Angular (and some other larger JavaScript frameworks) apart from BackboneJS is two-way data binding. Two-way data binding is the ability to allow your framework to create the relationship between your HTML and JavaScript, to allow a value changing on the client to be reflected in the data.

Two-way data binding is another feature of Angular, and a big plus for any JavaScript framework. Data binding is a very common task, so a framework taking on the work of abstraction is exactly the kind of thing a framework can be used for. If you're interested in how two-way data binding works in various frameworks there was a talk given at JSConfEU on just that subject covering Angular, Ember, and Knockout’s data binding methods.

Directives are a key feature in Angular that you’ve already seen, where you can create reusable components or use directives that come with the framework. There’s also a growing community of Angular modules for you to re-use, not unlike Ruby gems. Templating comes with the framework as well, and you’ll use regular HTML as your template – no need to fiddle with EJS, Jade, etc.

Angular provides its own testing runner, Karma. The Angular team prioritizes testing and makes it very easy to integrate testing into your project. Another feature Angular provides is dependency injection. You can read up on dependency injection on your own, but especially for testing, Angular providing mocks of heavy dependencies makes your app much more testable.

And of course, as a final evident strength, Angular is backed by a major industry player, Google. So even if it has not been around for long, a lot of the momentum comes from the power of that endorsement.

The greatest weakness of Angular is that is a quite different paradigm of writing client-side code than previously accepted. Once you start writing your markup vastly differently than HTML, your project is assuming you're going to continue using Angular or some other tool set that works in a similar way for some time. There are some ways of mitigating this risk, such as continuing to use standard HTML elements and attaching Angular behaviors with an attribute rather than an custom element.

Angular’s short history is another weakness – is it just the hot new thing, or has it been thoroughly put through its paces? Some are also skeptical of the Google backing, shying away from projects that have such ardent corporate support.

Angular will be dropping support for IE8 in 2014, as of Angular 1.3. The Angular team argues that their decision is parallel with jQuery, whose team released a 2.0 version that drops IE8 support. That means that you’d stick with the 1.2 version of Angular if you needed to maintain that support. After 1.3, the team will not be pushing bug fixes for that browser, and the fear of “abandonware” comes into play. If IE8 remains a requirement for your audience, then it’ll be very important to check on your support plan for this, and really any, JavaScript framework.

How big is it?

Angular is about 36kb compressed and minified. Google offers up use of their CDN copies for speed (but possibly and presumably tracking) purposes.

Angular in action: Sample app

I’ll show the same app functionality created in the Backbone chapter here in Angular. You’ll see a very simple list and show view of properties for the app for the client Realtors Inc.

The first step of making an Angular app is to define it so there’s something to reference in an ng-app attribute, where you tell Angular to pay attention:

JavaScript

var realtorsapp = angular.module('realtorsapp', [])

 

HTML

<html ng-app=”realtorsapp”>

I defined the app as a variable/object so I can add more pieces onto it later (controllers, directives, services), but you can chain these pieces onto your app as shown in the earlier “unicorn” directive. The brackets are for dependencies, not unlike RequireJS notation. Most of the time in Angular you’ll explicitly define your dependencies, where Angular is flexing its dependency injection muscles.

I put the ng-app attribute on the html element; ng-app is where you create your scope object for Angular, so putting it on the <body> tag (if you don’t need to modify the <title> tag, for example), or the DOM area you plan to manipulate with Angular could theoretically make your app marginally faster by limiting the world Angular needs to be aware of.

Data

Because Angular is more closely linked to the HTML, I’ll write out my list of properties in HTML first, and extract necessary logic as I go to start populating the page with my “real” data:

 

<table>

    <tr>

        <td><a href="#">123 Sunflower Lane</a></td>

        <td>20001</td>

        <td>$1M</td>

    </tr>

    <tr>

        <td><a href="#">123 Sunflower Lane</a></td>

        <td>20001</td>

        <td>$1M</td>

    </tr>

    <tr>

        <td><a href="#">123 Sunflower Lane</a></td>

        <td>20001</td>

        <td>$1M</td>

    </tr>

</table>

Angular has lots of contributed components available (one site to search for them is http://ngmodules.org/; I suspect a more formal site may emerge); since I’m using a table in this case, I could find an ng-table directive. However, the directives included in Angular are quite robust, so I can make a simple list using an ng-repeat, and tossing some data in an ng-init to prepopulate.

 

<table ng-init="properties=['123 Iris Lane','234 Sunflower Blvd','923 Azalea Rd']">

    <tr ng-repeat="property in properties">

        <td><a href="#">{{ property }}</a></td>

        <td>20001</td>

        <td>$1M</td>

    </tr>

</table>

I’d rather pull that object out of ng-init and into a JS file so I can add mrore properties/values. What I did, for demo purposes, was to put them directly into my $scope object (note, not a great idea outside of this, you’d probably fetch the data using the $http service).

 

realtorsApp.controller('PropertyController', [$scope, function($scope) {

    $scope.properties = [

        { address: '123 Sunflower Lane', zip: 20001, listingPrice: 200000 },

        { address: '983 Bluebell Lane', zip: 40503, listingPrice: 120000 },

        { address: '60 Iris Lane', zip: 19106, listingPrice: 350000 }

    ];

}]);

The $scope object is the world Angular keeps track of for that magical data-binding, the glue that allows Angular to do the heavy lifting of updating your view/model when the model/view changes.

Then I swapped the ng-init in my HTML for an ng-controller directive to use the PropertyController I just defined.

 

<table ng-controller="PropertyController">

</table>

Views and Routing

Templates in Angular are HTML (insofar as the HTML you’ve seen with {{ }} counts in that). That means I can break out my table into a separate view so that I can use the same space for showing a single property. I named this file listPartial.html, but the name is fairly arbitrary.

 

<table>

    <tr ng-repeat="property in properties">

        <td><a href="/#/property{{ properties.indexOf(property) }}">{{ property.address }}</a></td>

        <td>{{ property.zip }}</td>

        <td>{{ property.listingPrice | currency }}</td>

    </tr>

</table>

Angular routing was broken out into a separate module earlier this year, as the ngRoute module. Using ngRoute gives you access to the ngView directive and a couple $route[foo] services. I updated my cheater “backend” data so that I can make a show controller as well to reference in my route. Here’s the route:

 

realtorsApp.config(function($routeProvider) {

    $routeProvider.when('/', {

        controller: 'PropertyController',

        templateUrl: '/views/listPartial.html'

    })

    .when('/property/:propertyId', {

        controller: 'PropertyShowController',

        templateUrl: '/views/showPartial.html'

    })

    .otherwise({redirectTo: '/'});

});

 

And the “data” and controllers:

 

var properties = [

    { address: '123 Sunflower Lane', zip: 20001, listingPrice: 200000 },

    { address: '983 Bluebell Lane', zip: 40503, listingPrice: 120000 },

    { address: '60 Iris Lane', zip: 19106, listingPrice: 350000 }

];

 

realtorsApp.controller('PropertyShowController', ['$scope', '$routeParams',

    function($scope, $routeParams) {

        $scope.property = properties[$routeParams.propertyId];

    }

]);

 

realtorsApp.controller('PropertyController', ['$scope',

    function($scope) {

        $scope.properties = properties;

    }

]);

I added the $routeParams dependency to the show controller to leverage the id I’m seeing through the router so I can cheat and point at a property based on its position in the array, which you might’ve noticed happening in the listPartial’s href value.

Now I can go to my application’s list and show views, use the back button, etc. and Angular handles a lot behind the scenes. You can find the example of this app at XYZ and the source at XYZ.

Resources

Angular has been previously criticized for its documentation, both the lack thereof and the readability. That said, there’s plenty to read on http://docs.angularjs.org/guide/, http://docs.angularjs.org/api, and of course http://docs.angularjs.org/tutorial/.

Egghead.io is another popular resource with lots of video tutorials https://egghead.io/. Many videos are now behind a “pro” subscription wall, at about $15/month.

And of course, AngularJS Edge

There has been error in communication with Booktype server. Not sure right now where is the problem.

You should refresh this page.