Beginning with AngularJS

AngularJS is a structural framework for dynamic web apps. It lets you use HTML as your template language and lets you extend HTML's syntax to express your application's components clearly and succinctly. Out of the box, it eliminates much of the code you currently write through data binding and dependency injection. And it all happens in JavaScript within the browser, making it an ideal partner with any server technology.

Angular is what HTML would have been had it been designed for applications. HTML is a great declarative language for static documents. It does not contain much in the way of creating applications, and as a result building web applications is an exercise in what do I have to do to trick the browser into doing what I want.

The impedance mismatch between dynamic applications and static documents is often solved with:

  • a library - a collection of functions which are useful when writing web apps. Your code is in charge and it calls into the library when it sees fit. E.g., jQuery.
  • frameworks - a particular implementation of a web application, where your code fills in the details. The framework is in charge and it calls into your code when it needs something app specific. E.g., knockout, ember, etc.

Angular takes another approach. It attempts to minimize the impedance mismatch between document centric HTML and what an application needs by creating new HTML constructs. Angular teaches the browser new syntax through a construct we call directives. Examples include:

  • Data binding, as in {{}}.
  • DOM control structures for repeating/hiding DOM fragments.
  • Support for forms and form validation.
  • Attaching code-behind to DOM elements.
  • Grouping of HTML into reusable components.

A complete client-side solution

Angular is not a single piece in the overall puzzle of building the client-side of a web application. It handles all of the DOM and AJAX glue code you once wrote by hand and puts it in a well-defined structure. This makes Angular opinionated about how a CRUD application should be built. But while it is opinionated, it also tries to make sure that its opinion is just a starting point you can easily change. Angular comes with the following out-of-the-box:

  • Everything you need to build a CRUD app in a cohesive set: data-binding, basic templating directives, form validation, routing, deep-linking, reusable components, dependency injection.
  • Testability story: unit-testing, end-to-end testing, mocks, test harnesses.
  • Seed application with directory layout and test scripts as a starting point.

Angular Sweet Spot

Angular simplifies application development by presenting a higher level of abstraction to the developer. Like any abstraction, it comes at a cost of flexibility. In other words not every app is a good fit for Angular. Angular was built for the CRUD application in mind. Luckily CRUD applications represent at least 90% of the web applications. But to understand what Angular is good at one also has to understand when an app is not a good fit for Angular.

Games, and GUI editors are examples of very intensive and tricky DOM manipulation. These kinds of apps are different from CRUD apps, and as a result are not a good fit for Angular. In these cases using something closer to bare metal such as jQuery may be a better fit.

index.html

  • <!doctype html>
  • <html ng-app>
  •   <head>
  •     <script src="http://code.angularjs.org/1.0.6/angular.min.js"></script>
  •     <script src="script.js"></script>
  •   </head>
  •   <body>
  •     <div ng-controller="InvoiceCntl">
  •       <b>Invoice:</b>
  •       <br>
  •       <br>
  •       <table>
  •        <tr><td>Quantity</td><td>Cost</td></tr>
  •        <tr>
  •          <td><input type="number" ng-pattern="/\d+/" step="1" min="0" ng-model="qty" required ></td>
  •          <td><input type="number" ng-model="cost" required ></td>
  •        </tr>
  •       </table>
  •       <hr>
  •       <b>Total:</b> {{qty * cost | currency}}
  •     </div>
  •   </body>
  • </html>

Script.js

function InvoiceCntl($scope) {
  $scope.qty = 1;
  $scope.cost = 19.95;
}

Try out the Live Preview above, and then let's walk through the example and describe what's going on.
In the <html> tag, we specify that it is an Angular application with the ng-app directive. The ng-app will cause Angular to auto initialize your application.

<html ng-app>

We load Angular using the <script> tag:

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/?.?.?/angular.min.js"></script>

From the ng-model attribute of the <input> tags, Angular automatically sets up two-way data binding, and we also demonstrate some easy input validation:

Quantity: <input type="number" ng-pattern="/\d+/" step="1" min="0" ng-model="qty" required >
Cost: <input type="number" ng-model="cost" required >

These input widgets look normal enough, but consider these points:

  • When this page loaded, Angular bound the names of the input widgets (qty and cost) to variables of the same name. Think of those variables as the "Model" component of the Model-View-Controller design pattern.
  • Note that the HTML widget input has special powers. The input invalidates itself by turning red when you enter invalid data or leave the input fields blank. These new widget behaviors make it easier to implement field validation common in CRUD applications.

And finally, the mysterious {{ double curly braces }}:

     Total: {{qty * cost | currency}}

This notation, {{ _expression_ }}, is Angular markup for data-binding. The expression itself can be a combination of both an expression and a filter: {{ expression | filter }}. Angular provides filters for formatting display data.
In the example above, the expression in double-curly braces directs Angular to "bind the data we got from the input widgets to the display, multiply them together, and format the resulting number into output that looks like money."
Notice that we achieved this application behavior not by calling Angular methods, nor by implementing application specific behavior as a framework. We achieved the behavior because the browser behaved more in line with what is needed for a dynamic web application rather then what is needed for a static document. Angular has lowered the impedance mismatch to the point where no library/framework calls are needed.

The Zen of Angular

Angular is built around the belief that declarative code is better than imperative when it comes to building UIs and wiring software components together, while imperative code is excellent for expressing business logic.

  • It is a very good idea to decouple DOM manipulation from app logic. This dramatically improves the testability of the code.
  • It is a really, really good idea to regard app testing as equal in importance to app writing. Testing difficulty is dramatically affected by the way the code is structured.
  • It is an excellent idea to decouple the client side of an app from the server side. This allows development work to progress in parallel, and allows for reuse of both sides.
  • It is very helpful indeed if the framework guides developers through the entire journey of building an app: from designing the UI, through writing the business logic, to testing.
  • It is always good to make common tasks trivial and difficult tasks possible.

Angular frees you from the following pain:

  • Registering callbacks: Registering callbacks clutters your code, making it hard to see the forest for the trees. Removing common boilerplate code such as callbacks is a good thing. It vastly reduces the amount of JavaScript coding you have to do, and it makes it easier to see what your application does.
  • Manipulating HTML DOM programmatically: Manipulating HTML DOM is a cornerstone of AJAX applications, but it's cumbersome and error-prone. By declaratively describing how the UI should change as your application state changes, you are freed from low level DOM manipulation tasks. Most applications written with Angular never have to programmatically manipulate the DOM, although you can if you want to.
  • Marshaling data to and from the UI: CRUD operations make up the majority of AJAX applications. The flow of marshaling data from the server to an internal object to an HTML form, allowing users to modify the form, validating the form, displaying validation errors, returning to an internal model, and then back to the server, creates a lot of boilerplate code. Angular eliminates almost all of this boilerplate, leaving code that describes the overall flow of the application rather than all of the implementation details.
  • Writing tons of initialization code just to get started: Typically you need to write a lot of plumbing just to get a basic "Hello World" AJAX app working. With Angular you can bootstrap your app easily using services, which are auto-injected into your application in a Guice-like dependency-injection style. This allows you to get started developing features quickly. As a bonus, you get full control over the initialization process in automated tests.

Angular <script> Tag

This example shows the recommended path for integrating Angular with what we call automatic initialization.

<!doctype html>
<html xmlns:ng="http://angularjs.org" ng-app>
  <body>
    ...
    <script src="angular.js">
  </body>
</html>
  • Place the script tag at the bottom of the page. Placing script tags at the end of the page improves app load time because the HTML loading is not blocked by loading of the angular.js script. You can get the latest bits from http://code.angularjs.org. Please don't link your production code to this URL, as it will expose a security hole on your site. For experimental development linking to our site is fine.
    • Choose: angular-[version].js for a human-readable file, suitable for development and debugging.
    • Choose: angular-[version].min.js for a compressed and obfuscated file, suitable for use in production.
  • Place ng-app to the root of your application, typically on the <html> tag if you want angular to auto-bootstrap your application.
<html ng-app>
  • If IE7 support is required add id="ng-app"
<html ng-app id="ng-app">
  • If you choose to use the old style directive syntax ng: then include xml-namespace in html to make IE happy. (This is here for historical reasons, and we no longer recommend use of ng:.)
<html xmlns:ng="http://angularjs.org">

Automatic Initialization

Angular initializes automatically upon DOMContentLoaded event, at which point Angular looks for the ng-app directive which designates your application root. If the ng-app directive is found then Angular will:

  • load the module associated with the directive.
  • create the application injector
  • compile the DOM treating the ng-app directive as the root of the compilation. This allows you to tell it to treat only a portion of the DOM as an Angular application.
<!doctype html>
<html ng-app="optionalModuleName">
  <body>
    I can add: {{ 1+2 }}.
    <script src="angular.js"></script>
  </body>
</html>

Manual Initialization

If you need to have more control over the initialization process, you can use a manual bootstrapping method instead. Examples of when you'd need to do this include using script loaders or the need to perform an operation before Angular compiles a page.
Here is an example of manually initializing Angular:

 

<!doctype html>

<html xmlns:ng="http://angularjs.org">
  <body>
    Hello {{'World'}}!
    <script src="http://code.angularjs.org/angular.js"></script>
    <script>
       angular.element(document).ready(function() {
         angular.bootstrap(document, ['optionalModuleName']);
       });
    </script>
  </body>
</html>

Note that we have provided the name of our application module to be loaded into the injector as the second parameter of the api/angular.bootstrap function. This example is equivalent to using the ng-app directive, with ng-app="optionalModuleName", as in the automatic initialization example above.
This is the sequence that your code should follow:

  • After the page and all of the code is loaded, find the root element of your AngularJS application, which is typically the root of the document.
  • Call api/angular.bootstrap to compile the element into an executable, bi-directionally bound application.

HTML compiler
Angular's HTML compiler allows the developer to teach the browser new HTML syntax. The compiler allows you to attach behavior to any HTML element or attribute and even create new HTML elements or attributes with custom behavior. Angular calls these behavior extensions directives.

HTML has a lot of constructs for formatting the HTML for static documents in a declarative fashion. For example if something needs to be centered, there is no need to provide instructions to the browser how the window size needs to be divided in half so that the center is found, and that this center needs to be aligned with the text's center. Simply add an align="center" attribute to any element to achieve the desired behavior. Such is the power of declarative language.

But the declarative language is also limited, since it does not allow you to teach the browser new syntax. For example there is no easy way to get the browser to align the text at 1/3 the position instead of 1/2. What is needed is a way to teach the browser new HTML syntax.

Angular comes pre-bundled with common directives which are useful for building any app. We also expect that you will create directives that are specific to your app. These extensions become a Domain Specific Language for building your application.
All of this compilation takes place in the web browser; no server side or pre-compilation step is involved.

Compiler

Compiler is an angular service which traverses the DOM looking for attributes. The compilation process happens in two phases.

  • Compile: traverse the DOM and collect all of the directives. The result is a linking function.
  • Link: combine the directives with a scope and produce a live view. Any changes in the scope model are reflected in the view, and any user interactions with the view are reflected in the scope model. This makes the scope model the single source of truth.

Some directives such as ng-repeat clone DOM elements once for each item in a collection. Having a compile and link phase improves performance since the cloned template only needs to be compiled once, and then linked once for each clone instance.

Directive

A directive is a behavior which should be triggered when specific HTML constructs are encountered during the compilation process. The directives can be placed in element names, attributes, class names, as well as comments. Here are some equivalent examples of invoking the ng-bind directive.

<span ng-bind="exp"></span>
<span class="ng-bind: exp;"></span>
<ng-bind></ng-bind>
<!-- directive: ng-bind exp -->

A directive is just a function which executes when the compiler encounters it in the DOM.
Here is a directive which makes any element draggable. Notice the draggable attribute on the <span> element.


index.html

<!doctype html>
<html ng-app="drag">
  <head>
    <script src="http://code.angularjs.org/1.0.6/angular.min.js"></script>
    <script src="script.js"></script>
  </head>
  <body>
    <span draggable>Drag ME</span>
  </body>
</html>

script.js

angular.module('drag', []).
  directive('draggable', function($document) {
    return function(scope, element, attr) {
      var startX = 0, startY = 0, x = 0, y = 0;
      element.css({
       position: 'relative',
       border: '1px solid red',
       backgroundColor: 'lightgrey',
       cursor: 'pointer'
      });
      element.bind('mousedown', function(event) {
        // Prevent default dragging of selected content
        event.preventDefault();
        startX = event.screenX - x;
        startY = event.screenY - y;
        $document.bind('mousemove', mousemove);
        $document.bind('mouseup', mouseup);
      });
 
      function mousemove(event) {
        y = event.screenY - startY;
        x = event.screenX - startX;
        element.css({
          top: y + 'px',
          left:  x + 'px'
        });
      }
 
      function mouseup() {
        $document.unbind('mousemove', mousemove);
        $document.unbind('mouseup', mouseup);
      }
    }
  });

The presence of the draggable attribute on any element gives the element new behavior. The beauty of this approach is that we have taught the browser a new trick. We have extended the vocabulary of what the browser understands in a way which is natural to anyone who is familiar with HTML principles.

Understanding View

There are many templating systems out there. Most of them consume a static string template and combine it with data, resulting in a new string. The resulting text is then innerHTMLed into an element.

This means that any changes to the data need to be re-merged with the template and then innerHTMLed into the DOM. Some of the issues with this approach are: reading user input and merging it with data, clobbering user input by overwriting it, managing the whole update process, and lack of behavior expressiveness.

Angular is different. The Angular compiler consumes the DOM with directives, not string templates. The result is a linking function, which when combined with a scope model results in a live view. The view and scope model bindings are transparent. No action from the developer is needed to update the view. And because no innerHTML is used there are no issues of clobbering user input. Furthermore, Angular directives can contain not just text bindings, but behavioral constructs as well.

The Angular approach produces a stable DOM. This means that the DOM element instance bound to a model item instance does not change for the lifetime of the binding. This means that the code can get hold of the elements and register event handlers and know that the reference will not be destroyed by template data merge.








}