AngularJS is too humble to say you’re doing it wrong

For years, web application developers have used DOM manipulation tools like jQuery to control their user interface. Astute developers have taken it to the next level with client-side templating tools like Mustache and Handlebars.js to build sophisticated user interfaces on the client side.

And then AngularJS came along.

And we all realized we’ve been doing it wrong.

Way wrong.

The Old Way

Remember before you discovered AngularJS? Back when your code was organized like this:

HTML that defines your page JavaScript that downloads AJAX data HTML that defines a client side template

(yeah, this: <script type="text/html">...</script> ) JavaScript that renders the client-side template JavaScript that injects the rendered template HTML into the DOM

You thought that was pretty cool. “Hey look,” you said, “I’ve off-loaded template rendering to the browser!”. Yeah, you were pretty cool.

But then AngularJS showed you how you were wrong. You could accomplish the same client-side magic with a lot less code.

The New Way

Under AngularJS, your code can be organized like this:

HTML that defines your page and client-side templates inline JavaScript that downloads AJAX data

How does that even work? I mean, you’ve got like less than half of the bullet points now.

The answer: Data Binding.

Data Binding is the secret sauce of AngularJS (along with a couple dozen other delicious spices and condiments). Oh, and it’s not a secret at all. The code is actually pretty easy to read, despite being pure magic awesomeness on environmentally-friendly steroids.

Shall We Do Show-and-Tell?

The old way

This should be very familiar. You’ve got an HTML page, and you want to add some dynamic content with a client-side template:

Here’s the page HTML:

<html> <body> <div id="my-list-of-animals"> </div> </body> </html>

Let’s use Handlebars for the client-side template:

<script id="animal-template" type="text/x-handlebars-template"> <div> <div>{{animalName}}</div> <div>{{favoriteFood}}</div> </div> </script>

And you need some JavaScript to download the AJAX data, render the client side template, and inject it into the DOM:

$.get("/api/animals/", function(response) { var source = $("#animal-template").html(); var template = Handlebars.compile(source); $.each(response, function() { var html = template(this); $("#my-list-of-animals").append(html); }); });

Put all that together somehow, and wow, that’s a lot of code to do something that should be very simple.

That covers all 5 bullet points above. You’re still cool, right?

The AngularJS Way

Remember how there are only two bullet points. Well, here they are:

First, your page HTML:

<html ng-app> <body> <div ng-controller="MyAnimalController"> <div ng-repeat="animal in animals"> <div>{{animal.animalName}}</div> <div>{{animal.favoriteFood}}</div> </div> </div> </body> </html>

Did you see that? There’s no <script> hack. The template is right inside the page! Right there. In-line. Right where you wanted it all along, but never had the guts to ask. But I digress.

Second, the JavaScript:

function MyAnimalController($scope, $http) { $http.get("/api/animals/").success(function(response) { $scope.animals = response; }); }

And that’s it. It really is glorious. The AngularJS team really distilled the client-side template problem to its essence and produced an elegant solution. But don’t take my word for it. Check out the win list below.

Win List

Look at all the prizes you won by using AngularJS:

CSS classes are just for CSS now.

You used to abuse the HTML class attribute so you could find elements in the DOM with jQuery. Now, your class attributes are only for CSS. You don’t have to wonder anymore whether a particular class is used by JavaScript or CSS. The answer is always CSS: The way nature intended No <script> hacks.

You don’t have to trick the browser into ignoring your client-side templates anymore. Don’t you feel cleaner? Client side templates are cohesive with your page

You used to have a pile of client-side template files scattered throughout your project, or all crammed into your HTML <head>. Now they are right in the page, exactly where you wanted to read them in the first place. You don’t have to name every template

You used to name each <script> element with an “id” attribute to make it findable by jQuery. You can nuke those strings in your JavaScript and HTML, and not worry about them getting out-of-sync. You have control over the scope of your JavaScript

Previously you had to worry about your jQuery selectors casting too wide a net and selecting elements beyond what you intended. For example, suppose there happened to be an element in the page somewhere with class “animal”, and you didn’t know about it. Then you wrote a jQuery selector like $(“.animal”). Boom, you just mofidied an element you didn’t intend to. With AngularJS, your JavaScript cannot reach outside the ng-controller demarkation. You don’t have to remember to clean up HTML on refresh

Let’s say I want to refresh the animal list in this example. Under jQuery, I have to remember to do this: $("#my-list-of-animals").html("") before I start .append() ing new animals. In AngularJS, I just replace $scope.animals with the newly downloaded list, and it automatically clears out the old HTML. Your JavaScript is cleaner

Your JavaScript has no CSS selectors anymore. It used to be littered with strings to locate elemenents in the DOM. Now it’s just got business logic. Pure, sweet business logic. You can unit test your JavaScript without a DOM

I should have mentioned this first. Notice how my JavaScript has no knowledge of a DOM? It doesn’t even know there’s HTML involved at all. This makes it much easier to unit test, because you don’t need to load a big chunk of fixture HTML to test your JavaScript. AngularJS provides some great docs on testing too.

Almost Too Humble

I started reading about AngularJS and re-working parts of my projects to use it in earnest only a few weeks ago. A day into the effort, the light bulb went on for me:

I’ve been doing this all wrong

At that point, I started to wonder why the AngularJS team didn’t write article after article with the same title: “You’re Doing It Wrong”. And that’s what inspired me to write this.

So there you have it. An opinionated blog post about an opinionated framework.