Table of contents

< Previous chapterNext chapter >

Last updated .

Forward from the first Hello World sample

It is good practice to separate presentation and logic as much as possible, so I moved the code that creates the root module to a separate app.js file, located in the Scripts folder. I also took the chance to add something called a controller, which hopefully will make sense in a short while:

// Create the root module (app) ( function () { var app = angular.module('AngularProject', []); // Create some controller app.controller("myController", MyController); function MyController() { var vm = this; vm.FirstName = "Albert"; vm.SurName = "Einstein"; } } )();

In the code above, the same AngularProject module as before is being registered, but there is also a controller being created. It exposes an object with FirstName and SurName properties with some default values. Now, I can update the view (i.e. the html) to make use of the controller. This requires adding an ng-controller directive to an appropiate html element. The property values are displayed on the page, but there is also an input field allowing the user to update the surname property:

<!doctype html> <html ng-app="AngularProject"> <head> <title>Home</title> <meta charset="utf-8" /> <script src="Scripts/Angular/angular-1.5.0-rc.0/angular.js"></script> </head> <body ng-controller="myController as vm"> <input type="text" ng-model="vm.SurName"/> <p>Name is {{vm.FirstName}} {{vm.SurName}}</p> <script src="Scripts/App.js"></script> </body> </html>

If you want to follow along, you should create an App.js file in the Scripts folder and add the script listed above. You should also update the Home.html file with what is shown above. That will give you the chance to observe in the browser how the displayed name is being updated automagically as you type a new name in the input box:

Data binding ensures the displayed name is updated
Data binding ensures the displayed name is updated

The html with interspersed Angular directives is what the Angular documentation refers to as a "template". What you see in the browser is then termed the view.

There are many things to digest from this example. First, regarding the script code, it adds a controller to the app module of the name "myController", which is defined with the function called MyController. You can think of the latter as a constructor for the controller object. Inside, two properties are declared and initialized with some default values (the names). In the markup, I have added an ng-controller directive (attribute) to the body tag. This essentially tells Angular that the specified object is the controller for everything Angular inside the body tag, including descendant elements. The syntax for doing this is ControllerName as vm, where vm is the symbol that can then be used to reference the viewmodel - vm is short for viewmodel.

Now, the input box is intended to represent the SurName property of the viewmodel. This is accomplished by setting an ng-model directive on the element, telling it which property to reference - in this case the SurName property of the viewmodel. Similarly, the values of both of the properties are inserted into the paragraph element by two Angular expressions, again using the viewmodel object that was established in the body tag. An Angular expression is enclosed in double curly brackets.

Moreover, notice the use in the script of the vm variable instead of just using this. This is a convention and helps to avoid confusion if nested functions also use the this keyword. Also, the entire script is wrapped in an IIFE (immediately-invoked function expression) construct in order to execute the code immediately and to encapsulate its scope. This is also a commonly used and sensible convention.

This example essentially illustrates the one-way and two-way data binding that can be accomplished with an Angular.js controller. No doubt, it is perfectly possible to do the same without using Angular.js, but not without some custom script, including event handlers. The ng-model directive is used with an input control and sets up two-way data binding: when the user types in the input box, the binding causes the associated data in the data model to be updated. And conversely, if the data model changes, so does the value of the input box. One-way data binding is exemplified by the Angular expressions in double curly brackets: When the data in the data model change, so does the display. There is also a one-time binding. This is like one-way data binding, except it is done only once, and then the link between the UI element and the data model is gone. Such a one-time binding is defined like a one-way binding, but with two leading ':' characters, e.g. ::vm.FirstName.

The markup code listed above represents, in my view, a nice mix of UI elements and chunks of model data. If you have worked on an ASP.Net MVC project, you should see immediate similarities between the markup shown and what you might see in an equivalent Razor view file. But also some notable differences. The ng-controller directive would correspond to the Razor @model directive, in that they both introduce a symbol for the model. But, unlike with ASP.Net MVC, in the present example, the view specifies its controller; not the other way round. In fact, in Angular, the viewmodel (vm) is the controller. Setting the model property for the input field in the example with ng-model is somewhat akin to using a @Html.TextBox construct in Razor, and outputting the model data with Angular expressions (using double curly brackets) is like using a Razor expression (using @).

As an aside, this example has used the "controller as" syntax for specifying a controller, but there is an alternative way involving something called $scope ( Angular prefixes names of public objects with $ To prevent accidental name collisions). The former syntax is preferred for several reasons, which is why I will not confuse matters by describing the latter one, but you can read more on it here.

New stuff

Directive: Angular directives extend html and apply special behavior to attributes or elements.

ng-controller: A controller represents the C in MVC and serves to expose functionality to the view and bind the model with the view. The ng-controller directive takes the name of a controller function and an alias for that function.

ng-model: The ng-model directive binds input elements (and the like) with data. It also serves other functions sush as validation and keeping control state.

Angular expression: An Angular expression is enclosed in double curly brackets and is a way to embed javaScript-like code inside html. An expression can reference a controller alias to accomplish one-way data binding. The result of the expression is inserted in the DOM at the point of the expression.

One-way binding: Is implemented with an Angular expression that outputs a piece of model data and ensures that the displayed value is in sync with the model, for example: {{ vm.Name }}.

One-time binding: Is implemented with an Angular expression that outputs a piece of model data and ensures that the displayed value is in sync with the model, but only the first time around, for example: {{ ::vm.Name }}.

The Angular binding of UI elements with controller data is reminiscent of binding in a WPF application, there is even a parallel with the two-way/one-way/one-time variations.

The whole separation of markup and its supporting code into two files - the html and the script file - makes me think of the similar principle in ASP.Net with the markup in one (aspx) file and the supporting code in a "code-behind" file.

Event handling

It is arguably a bad idea to mix presentation (markup) with application logic. Nevertheless, this is exactly what Angular.js does, or at least enables you to do, by specifying event handlers for an element directly in the markup. This concept is strikingly similar to the good old onclick etc. attributes on html elements. The difference is, in the case of Angular, the event handler is a method on the controller. I have changed the example code to illustrate handling the click on a button:

<!doctype html> <html ng-app="AngularProject"> <head> <title>Home</title> <meta charset="utf-8" /> <script src="Scripts/Angular/angular-1.5.0-rc.0/angular.js"></script> </head> <body ng-controller="myController as vm"> <p id="nameInfo"></p> <p id="eventInfo"></p> <button id="myButton" ng-click="vm.myButton_click($event)">Click me!</button> <script src="Scripts/App.js"></script> </body> </html>

And the updated script code:

// Create the root module (app) ( function () { var app = angular.module('AngularProject', []); // Create some controller app.controller("myController", MyController); function MyController() { var vm = this; vm.FirstName = "Albert"; vm.SurName = "Einstein"; vm.myButton_click = function (e) { document.getElementById("nameInfo").innerHTML = "Name is " + vm.FirstName + " " + vm.SurName; document.getElementById("eventInfo").innerHTML = "" + arguments.length + " argument(s), target: " + e.target.id; }; } } )();

The above example illustrates how a handler for the click event can be established with the ng-click directive. It can contain an expression or call a method on the controller. I used the latter option to call the event handler that I named "myButton_click". To get access to the event argument inside the event handler, you muss pass it to the event handler using the identifier $event. With that, the event handler method has access to the properties of the event argument as well as to the controller properties and methods. When the button is clicked, this is what the user sees:

Clicking a button
After clicking the button

If you want to try it yourself, you can copy the markup and script from the above listings to your own files and view the html file in a browser.

As you might expect, there are also ng-mousedown, ng-keyup etc directives for other event types. Interestingly, some of these (ng-blur, for example) are absent from the intellisense dropdown list in my Visual Studio editor, but they otherwise do exist.

New stuff

ng-click: The ngClick directive allows you to specify a handler for the click event on an element.

< Previous chapterNext : Displaying collections with ng-repeat >


2016 by Niels Hede Pedersen Linked in