This is a preview-quality chapter of our continuously deployed eBook on AngularJS for .NET developers. You can read more about the project at http://henriquat.re. You can also follow us on twitter (Project: @henriquatreJS, Authors: @ingorammer and @christianweyer)

 

The Two Minute Guide to AngularJS for .NET Developers

While the allure of writing applications - and not just web sites - in HTML5 and JavaScript reaches a lot of developers, we've experienced that a number of developers are rather frightened by the idea of creating large applications in a dynamic language. In addition to the dynamic nature of JavaScript, the lack of a container-based GUI framework (which isolates causes and effects to individual controls, as it is done in the .NET Framework) and the general overarching flexibility and lack of guiding principles didn't make this environment too appealing for a lot of business developers.

We think that AngularJS can change this and we'd like to present a small sample of AngularJS code, the underlying markup and the resulting mini-application. (We're not going to talk too much about the individual steps in this sample, as this would be the focus of the next chapter.)

AngularJS Hello, World

This is quite likely the simplest possible AngularJS application.

<script src="http://code.angularjs.org/1.0.5/angular.js"></script>

<div ng-app>
    Name: <input type=text ng-model="name">
    <br>
    Current user's name: {{name}}
</div>

The interesting thing to note is that, apart from embedding Angular itself, there is actually no custom script running. In this sample, we have instead just used the standard AngularJS data binding without any custom processing. To activate angular for a particular <div>, it is enough to just use the custom attribute ng-app (which scopes the application to this particular HTML element). After this, we could simply use ng-model="name" to bind a certain input element to our view model and could then reference the model's value in other parts of the HTML code with the read-only expression {{name}}.

Adding a Controller

In a real application you will of course want to run custom code. To do this, AngularJS uses the concept of Controllers. A controller is an object which is instantiated for a certain view and which provides the business logic code for it. In addition, it sets up the initial view model which is used for data binding. (In the example above, we've used an implicitly created view model in Angular's automatically created root data binding scope).

In AngularJS, a controller is just a regular JavaScript constructor which accepts a magic $scope parameter (we're going to talk about this form of dependency injection in the following chapter.)

function MyController($scope) {
}

The $scope variable is the equivalent of a .NET DataContext which is used to establish the root of any data binding expression which used in the corresponding HTML markup. You could for example add a user object to bind your values to:

function UserController($scope) {

   $scope.currentUser = {
      firstName: "John",
      lastName: "Doe"
   };

}

To associate a certain controller with an HTML fragment, you have to add the ng-controller attribute to it to reference the desired controller.

<div ng-app ng-controller="UserController">
    First Name: <input type=text ng-model="currentUser.firstName"> <br>
    Last Name: <input type=text ng-model="currentUser.lastName"><br>
    Full Name: {{currentUser.firstName}} {{currentUser.lastName}}
</div>

When you start this application, you'll see that the model values are displayed and are correctly bound.

Automatic Change-Tracking in Model

One of the big differences between AngularJS and other JavaScript frameworks is how change tracking is implemented internally. In Angular, the underlying model does not have to be constructed in a special way. (In fact, as you've seen in the very first demo, AngularJS can even create an empty default model on the fly.) Your application does not have to expose any events or trigger any callbacks.

Instead, you can simply add methods to your model classes which perform the necessary data combination and/or retrieval:

function UserController($scope) {

   $scope.currentUser = {
      firstName: "John",
      lastName: "Doe"
   };

   $scope.getFullName = function() {
      return $scope.currentUser.firstName + " " + $scope.currentUser.lastName;
   };
}

You can then change the HTML markup to directly bind to the result of this method:

<div ng-app ng-controller="UserController">
    First Name: <input type=text ng-model="currentUser.firstName"> <br>
    Last Name: <input type=text ng-model="currentUser.lastName"><br>
    Full Name: {{getFullName()}}
</div>

Running this application will demonstrate the same behavior as before:

Please note that you could also add the method directly to your model object and bind to currentUser.getFullName() as will be shown in the following sample. Alternative approaches which will result in substantially more reusable code will rely on AngularJS' service concept, which we'll discuss in the next chapter.

Binding to Hierarchical Models

One common scenario which has been hard to implement in JavaScript applications (without the use of frameworks) is the display of editable master/detail data. AngularJS makes this very easy as well. In fact: if you're coming from a either WPF or Silverlight, you'll quite likely recognize the constructs used here as well.

I'll first show you the application which we're going to discuss. In this simple scenario, you can select one user from a list and can then edit details of the selected entry. Please observe how the user's full name in the list and underneath the textboxes is immediately updated whenever you type a value.

In this sample, I've first added a constructor (in C# terms, the closest equivalent would be a very simple class) which holds user instances and which returns a user's full name:

function User(firstName, lastName) {
   this.firstName = firstName;
   this.lastName = lastName;

   this.getFullName = function () {
      return this.firstName + " " + this.lastName;
   }
}

The corresponding controller populates a list of user, and then exposes two new properties to the view. The first one is called currentUser which reflects the currently selected user (the one for which the details should be shown). The second exposed element is the method selectUser which can be called by the view to select a different user as the current one.

function UserController($scope) {
   $scope.userList = [
      new User("John", "Doe"),
      new User("Henri", "de Bourbon"),
      new User("Marguerite", "de Valois"),
      new User("Gabrielle", "d'Estrées")
   ];

   // select the first user of the list
   $scope.currentUser = $scope.userList[0];

   // expose a callable method to the view
   $scope.selectUser = function (user) {
      $scope.currentUser = user;
   }
}

To display these values in the desired form, the following HTML fragment is used:

<div ng-app ng-controller="UserController">
    <b>Names</b>
    <ul>
        <li ng-repeat="user in userList">
            <a ng-click="selectUser(user)">{{user.getFullName()}}</a>
        </li>
    </ul>
    <hr>

    <b>Selected User</b><br>
    First Name: <input type=text ng-model="currentUser.firstName"> <br>
    Last Name: <input type=text ng-model="currentUser.lastName"><br>
    Full Name: {{currentUser.getFullName()}}
</div>

The attribute ng-repeat is used to perform the equivalent of a for or foreach loop. The HTML element which defines this attribute will be added for each individual entry of the list (in this case userList) while the inner elements will get access to the current item using the loop variable (in this case user).

Inside of the loop, we've included the following HTML fragment:

<a ng-click="selectUser(user)">{{user.getFullName()}}</a>

The attribute ng-click contains the name of a method on the view model ($scope) which will be called when the user clicks the element. As a parameter, the current value of the loop-variable user will be passed to the view model's method so that it knows which entry has been clicked on.

Extending HTML

Now, of course we can't easily extend HTML (as in the HTML5 specification) itself, but what AngularJS allows you, is to define new custom tags and use them alongside your regular HTML. Or to say it differently: you can build your own domain-specific extensions on top of HTML. These tags will be interpreted at runtime by AngularJS and will be converted into real HTML which is then rendered for the browser.

AngularJS calls an extension to HTML a directive. One of the canonical and simple example for a directive is the creation of tabbed dialogs, which can then be used inside your HTML like shown in the following example (the underlying directive's source code is conveniently part of AngularJS current official demos and the CSS used for displaying/styling the tab control is taken directly from Twitter's bootstrap project):

<div ng-app="myApp" class="myApp">
    <tabs>
        <pane title="First Page">
            This is some <i>content on the first page</i>.
        </pane>
        <pane title="Second">
            And this is the second page.
        </pane>
    </tabs>
</div>

Even though the HTML5 specification does not know about the elements tabs and pane, AngularJS allows you to register a directive (shown in a later chapter in full source code) which performs the necessary translation to the required HTML. The important thing to note is that this transformation is self-contained and completely independent from either your controller (which contains your application's business logic) or your HTML code (which contains your markup for one particular view). You can therefore reuse these directives similar to WPF or Silverlight's UI Controls.

Please note: this is a very simple initial demo and you can use AngularJS' directives in ways which are a lot more powerful than this. You can read more about directives and how to use them in one of the following chapters. Just as a bit early of mouth watering: directives can participate in two-way databinding so that you can, for example, embed jQuery UI's datepicker (or mostly any other component of most web frameworks) in a custom HTML element like <datePicker ng-model="user.dateOfBirth> .

Summarizing

In this short introduction, we've just wanted to quickly outline some of the capabilities of AngularJS. The two elements which might be the most important for business apps are:

  • AngularJS does not force a specific structure for models. You can use any kind of JavaScript objects. Changes will be tracked internally and the view/model binding works transparently in a bidirectional way.
  • AngularJS shields your business code from any DOM manipulation code. There is for example no need to explicitly bind to JavaScript events after a certain template has been rendered which would be necessary for jQuery-based code.

Oh, and by the way: AngularJS is extremely customizable, too. If you don't like any of its defaults, you'll see how you can change them in the upcoming chapters. Also, if you're very concerned about the validity of your HTML code, please rest assured that there is a solution for you as well. Even if it might not be as relevant for applications as it is for classic, content-based web sites, there are ways to specify all of Angular's attributes without breaking any HTML validators. This is performed mainly by using valid constructs like data-ng-xx instead of ng-xx or similar.

 

This was a preview-quality chapter of our continuously deployed eBook on AngularJS for .NET developers. If you enjoyed this chapter, you can read more about the project at http://henriquat.re. You can also follow us on twitter (Project: @henriquatreJS, Authors: @ingorammer and @christianweyer)