Learning AngularJS for .NET Developers

4.5 (2 reviews total)
By Alex Pop
    Advance your knowledge in tech with a Packt subscription

  • Instant online access to over 7,500+ books and videos
  • Constantly updated with 100+ new titles each month
  • Breadth and depth in over 1,000+ technologies
  1. Introducing AngularJS

About this book

AngularJS is the most popular JavaScript MVC framework, and it embraces and extends HTML rather than abstracting it. The building of single-page applications is a web-designer-friendly process with the AngularJS expressive HTML vocabulary. It drastically reduces the amount of JavaScript required to control complex user interactions and enforces a modular approach to structuring your JavaScript code.

This book covers all of the stages of building a single-page web application, starting with frontend components powered by AngularJS, continuing with web services that leverage ServiceStack, and putting it all together in an ASP.NET MVC application. You will learn a development process focused on rapid delivery and testability for all application layers.

Publication date:
July 2014
Publisher
Packt
Pages
202
ISBN
9781783986606

 

Chapter 1. Introducing AngularJS

In this chapter, we will learn how to manipulate HTML using AngularJS and will also learn about the core parts of AngularJS. A series of examples will gradually showcase the main AngularJS features. After a high-level overview of the AngularJS architecture, more complex examples will be shown, allowing the reader to see how data binding works and how to respond to user events. The chapter will continue with an overview of the JavaScript patterns that are essential for AngularJS applications, followed by an overview of AngularJS building blocks. The list of topics explored in this chapter is as follows:

  • Presenting AngularJS with examples

  • Controllers

  • An overview of the AngularJS architecture

  • JavaScript patterns and practices for AngularJS

  • Dependency injection

  • Services

  • Directives

  • Filters

The version of AngularJS used in this book is 1.2 because it is the latest version that will support Internet Explorer 8. .NET developers often have to support corporate clients that use older Internet Explorer versions, and this needs to be taken into account when planning the AngularJS adoption. You will see references to AngularJS Version 1.2.15 throughout the book, but all of the code should be compatible with any newer 1.2.x version that is available when you are reading this material.

All of the code examples from this chapter are also hosted online with HTML, CSS, and JavaScript editors at http://plnkr.co. This editor is built with AngularJS and is a great tool to share examples and isolate frontend application parts when using collaboration sites such as http://stackoverflow.com. For convenience, the code from this book is also hosted on GitHub in two repositories: http://github.com/popalexandruvasile/angularjs-dotnet-book (for individual examples used to introduce specific concepts) and http://github.com/popalexandruvasile/rentthatbike (for the main application example that will be built incrementally throughout the book). The code for this chapter can also be found at http://github.com/popalexandruvasile/angularjs-dotnet-book/tree/master/Chapter1.

I recommend using the Google Chrome browser for the examples in this book. It has an extension called AngularJS Batarang, which will reveal additional information about the AngularJS objects loaded in the current browser session. When using this extension on http://plnkr.co, you need to open the example in a separate browser window for best results. This extension will be explored in Chapter 5, Testing and Debugging AngularJS Applications, so that you can use the details mentioned there to set it up.

Before discussing AngularJS, it is worth mentioning that this framework comes with online documentation in the form of a developer guide at http://code.angularjs.org/1.2.15/docs/guide, and its API is documented at http://code.angularjs.org/1.2.15/docs/api. As this book is not an in-depth guide to AngularJS, you might find these links useful to gain more insight into the concepts and API explored here.

 

Presenting AngularJS with examples


The best way to present AngularJS is to explore a couple of examples first. I will then introduce the key AngularJS concepts showcased in these examples.

A jQuery example

Let's compare and contrast an example of a web page built with jQuery against an example of the same page built with AngularJS. The web page allows the user to enter a name and select a favorite color, and it will display formatted markup that reflects the entered values. The end result is shown in the next screenshot:

The following first code example is jQuery-based, with initial HTML content and additional behavior injected into the $(document).ready() event:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title>Chapter1 Example1</title>
  <script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
</head>
<body>
  <h1>Introduction</h1>
  <label>My name:</label>
  <input id="input-name" type="text" placeholder="Please enter name" />
  <br />
  <label>My favorite color:</label>
  <select id="select-color">
    <option>Please select</option>
    <option>red</option>
    <option>yellow</option>
    <option>magenta</option>
  </select>
  <h3 id="heading-name" style="display:none">Hello! My name is <span id="span-name"></span>.</h3> 
  <h3 id="heading-color" style="display:none">
    My favorite color is <span id="span-color">&nbsp;&nbsp;</span>.</h3>
<script>
  $(document).ready(function() {
    $("#input-name").keyup(function() {
      var name = $("#input-name").val();
      if (name) {
        $("#span-name").text(name);
        $("#heading-name").show();
      } else {
        $("#heading-name").hide();
      }
    });
    $("#select-color").change(function() {
      var color = $("#select-color").val();
      if (color != "Please select") {
        $("#span-color").css('background-color', color);
        $("#span-color").attr('title', color);
        $("#heading-color").show();
      } else {
        $("#heading-color").hide();
      }
    });
  });
</script>
</body>
</html>

You can view the preceding example either online at http://plnkr.co/edit/6wJ10DpmGhLIyWMxI3eP or in the Example1 folder from the source code for this chapter.

You will notice in the preceding example that we had to prepare the HTML markup for jQuery integration by having the id attributes set for specific elements. The JavaScript code binds to element events and will react to changes in user input, displaying the formatted content for valid entries and hiding it for invalid ones. JavaScript code is separated from HTML content, and the number of lines for each section is comparable.

An AngularJS example

The second example shown in the following code is based on AngularJS, and the functionality is identical to the previous example (try to ignore the highlighted element attributes for the moment, and the variables surrounded by curly brackets will be discussed later in this book):

<!DOCTYPE html>
<html ng-app>
<head>
  <meta charset="utf-8" />
  <title>Chapter1 Example2</title>
  <script src="http://code.angularjs.org/1.2.14/angular.js"></script>
</head>
<body>
  <h1>Introduction</h1>
  <label>My name:</label>
  <input type="text" placeholder="Please enter name" ng-model="name">
  <br/>
  <label>My favorite color:</label>
  <select ng-model="color">
    <option value="">Please select</option>
    <option>red</option>
    <option>yellow</option>
    <option>magenta</option>
  </select>
  <h3 ng-show="name">Hello! My name is {{name}}.</h3>
  <h3 ng-show="color">My favourite color is 
  <span title="{{color}}" style="background-color:{{color}};">&nbsp;&nbsp;</span>.</h3>
</body>
</html>

You can view the preceding example either online at http://plnkr.co/edit/yQ3WAJ8XKwtaFDnKWiCU or in the Example2 folder from the source code for this chapter. If you executed the previous example, you might have noticed a slight delay between when the name was entered and when it was displayed further down the page. This delay disappears in the AngularJS example due to its faster DOM manipulation.

You will notice that the HTML section does not have any id element attribute set, and there is no JavaScript code section. The only JavaScript reference is to the AngularJS core file that links to the current stable version of the framework. There are new element attributes, all prefixed with ng-. This prefix marks the built-in AngularJS extensions to the HTML vocabulary, also known as directives, and this prefix will appear often in the HTML code snippets throughout this book. This approach to extend the HTML markup by defining new element attributes, or even new elements, transforms it into meaningful and expressive markup, which is one of the major differentiating factors from a jQuery-based approach or from other JavaScript frameworks. By removing the boilerplate code from the jQuery example, AngularJS allows the developer to be more productive and use markup instead of code as much as possible. It also enables the sharing of HTML markup with a designer in a collaborative workflow, where HTML markup and JavaScript code are loosely coupled and not linked as tightly together as in the jQuery example through special element identifiers and CSS classes.

The first AngularJS-specific, most distinctive HTML attribute is ng-app. It sets the boundaries of the AngularJS application and can be applied on any HTML element, with the only constraint being that it can appear only once. The HTML element with the ng-app attribute is the AngularJS application root element. AngularJS will parse the markup delimited by the application root element and look for any ng- prefixed elements, attributes, or CSS classes. It will match some regular HTML tags such as input and select if they contain ng- prefixed attributes or CSS classes. These entities will then be mapped to instances of special AngularJS components called directives.

The directives are used to add dynamic behavior to HTML content and introduce a powerful, versatile, and declarative user interface definition language. Even the initial ng-app attribute maps to a directive used to bootstrap the AngularJS application. The next highlighted attribute in the example is ng-model. This attribute introduces the concept of scope, the fundamental data model in AngularJS.

All HTML elements in an AngularJS application will be associated with at least one instance of an object called scope. Scope is the special ingredient that links the view, as represented by HTML elements, to the code behind the view, represented in this example by directives. The scope object is initialized and owned by AngularJS components, and the view can only reference properties and functions of the scope object.

The application root element will be associated with the initial scope of the application. This initial scope is called the root scope, and any AngularJS application will have at least one scope: the instance of the root scope. Since some directives have their own scope instance created for them implicitly, a typical AngularJS application will have a hierarchy of scopes, with the root scope at the top.

Going back to the AngularJS example, the first ng-model attribute maps the value of the current input element to a property on the current scope instance. In our case, this specific property is the name property of the root scope. The name property is not defined anywhere prior to the ng-model attribute, and it will be created implicitly for the underlying scope instance by AngularJS. The mechanism where the value of a scope property and the value of an HTML element can update each other is called two-way data binding, and its signature in AngularJS is the ng-model attribute.

The next highlighted ng-model attribute maps the value of the select element to a new property of the current scope called color. The attribute is used in two different HTML elements, and its effect is similar—as soon as the user enters their name or selects a color, the changed values get stored as distinct properties on the current scope instance.

This concludes the data entry part of the example. The next part is about data display, and we start with the highlighted ng-show attribute. To understand the functionality introduced here, we have to discuss AngularJS expressions first.

An AngularJS expression is similar to a JavaScript expression used in the eval() function call. It is always evaluated against the current scope, and it can reference a scope property or more scope properties linked by logical operators. An AngularJS expression will ignore null or undefined scope properties, and this is another important difference from an equivalent JavaScript expression. In our example, the ng-show expression would not have generated an exception if the name scope property had not been defined previously.

The directive introduced by the ng-show attribute will show or hide its HTML element depending on the true or false evaluation of the expression from the attribute value. When the name property gets a nonempty value following user text input, then the first h3 element is displayed.

The next highlighted HTML snippet is {{name}}. This represents an interpolation that is based on an AngularJS expression that will be evaluated against the scope object and displayed as text inside the h3 tag. Interpolation is similar to one-way data binding from other templating systems, and it has the same outcome of a code expression being transformed into a string. The difference is that interpolation can use any valid AngularJS expression, and it accepts a value like {{name + ' and I am explaining Example2'}}.

The interpolation expression will reflect a change in the name scope property following user text input. We can start to visualize the flow of data from the input element through AngularJS and back to the h3 element.

The second h3 element is similar to the first one and bound to the color scope property instead. The first binding expression is an attribute value, and the second one is part of an attribute value. The fact that we can have a binding on HTML content—text, attribute, and even element tag—shows the power and versatility of AngularJS.

The following diagram shows the data flow from Example2:

The preceding diagram mentions the model and view as the two distinct concepts associated with the data binding and interpolation mechanism, and they will be explored in detail after we discuss the next AngularJS component.

Introducing the AngularJS controller

We will expand the previous example to include additional logic. The example will count how many times the color was changed, and it will display the count when it is greater than one, as shown in the following screenshot:

The following example contains new AngularJS directives and components that support the additional logic, as highlighted:

<!DOCTYPE html>
<html ng-app>
<head>
  <meta charset="utf-8" />
  <title>Chapter1 Example3</title>
  <script src="http://code.angularjs.org/1.2.14/angular.js"></script>
</head>
<body ng-controller="ExampleController">
  <h1>Introduction</h1>
  <label>My name:</label>
  <input type="text" placeholder="Please enter name" ng-model="name">
  <br/>
  <label>My favorite color:</label>
  <select ng-model="color" ng-change="onColorChanged()">
    <option value="">Please select</option>
    <option>red</option>
    <option>yellow</option>
    <option>magenta</option>
  </select>
  <h3 ng-show="name">Hello! My name is {{name}}.</h3>
  <h3 ng-show="color">My favourite color is 
  <span title="{{color}}" style="background-color:{{color}};">&nbsp;&nbsp;</span>.</h3>
  <div ng-show="colorChangeCount > 0">The favorite color was changed {{colorChangeCount}} times.</div>
<script>
  function ExampleController($scope) {
    $scope.colorChangeCount = 0;
    $scope.onColorChanged = function() {
      $scope.colorChangeCount++;
    };
  }
</script>
</body>
</html>

You can view the preceding example either online at http://plnkr.co/edit/5xW4MplFbcnTzMeO1jov or in the Example3 folder from the source code for this chapter.

The first highlighted attribute, ng-controller, introduces a directive that maps an AngularJS object called controller to the HTML section delimited by the current element. The controller is defined in the highlighted script tag as a globally accessible function. We call this function the controller constructor function. Note the $scope parameter that represents the current scope instance. This parameter gets initialized automatically by AngularJS, so when the controller constructor function is executed, the scope is available and ready to use. Declaring a parameter in a component definition and expecting AngularJS to automatically provide it is the signature of the dependency injection mechanism, which will be explored in detail in this chapter.

The scope passed to the controller is also attached to the view represented by the HTML element with the ng-controller attribute. The controller and view share data through the model represented by the scope instance. Any property defined on the controller scope will also be visible to the HTML view.

The first scope property is colorChangeCount. The second property is the onColorChanged function, which increments colorChangeCount when called. The two properties are a typical example of the custom logic found in an AngularJS controller.

Going back to the HTML from the previous example, the next highlighted snippet is the attribute, ng-change. This maps to a directive that will evaluate the expression value of the attribute every time the selection changes. This directive can also be used with input elements and requires the existence of the ng-model attribute. In our example, the ng-change attribute value is the onColorChanged() expression. AngularJS expressions might contain function calls, which are convenient when the expression being evaluated is too long or complex to be used as an attribute value.

This wraps up the data entry section of the controller logic. Next, we move on to the data visualization part, and you will notice that the first scope property is referenced by the HTML view in an ng-show attribute and in the {{colorChangeCount}} binding. The directive mapped to ng-show evaluates the property when changed, and a subsequent message is displayed if the property value is greater than zero or otherwise hidden.

I have updated the previous diagram for Example2 to reflect only what has been changed in Example3, as follows:

The darker arrows show the flow of data from the view to the model via the onColorChanged() method triggered by the select element change event. The model is updated in this method, and the change flows back to the view again through the colorChangeCount property. Note how the controller is not explicitly mentioned here as it does not have an active role in the data binding mechanism in AngularJS other than initializing the model represented by scope data properties and methods.

Another mechanism worth mentioning is the dirty checking process where AngularJS detects changes triggered by user interaction and propagates them as part of the scope life cycle by calling the scope.$apply method. Changes that occurred in scope properties or that have an effect on any expression are propagated within the scope.$digest method, which is called at the end of the $apply method. Any controller or directive can observe the changes in scope properties using the scope.$watch method, and these changes are propagated when the scope.$digest method is called as part of the scope life cycle.

Note

You can find more information on the scope life cycle and how changes are detected and propagated by AngularJS at http://code.angularjs.org/1.2.15/docs/guide/scope.

We now have a full working example that showcases the key concepts from AngularJS with the controller as the main vehicle to implement business logic and react to user input through the scope methods. It is now time to reveal the concepts underlying the first AngularJS examples in the next section.

An overview of the AngularJS architecture

The code for Example1 from the previous section was focused on jQuery and is representative of the JavaScript code that was at large when AngularJS was created. The example code has the manipulation of HTML elements intertwined with business logic. This makes it difficult to test the business logic in isolation from the presentation logic. Any change in application data or user input has to be manually propagated back and forth to the view represented by HTML elements. Compared to the AngularJS example, there is a lot more code that needs to be written, and this code might be difficult to scale and reuse.

JavaScript frameworks such as Backbone.js, knockout.js, AngularJS, and others addressed the problems of scalability, reusability, and testability by embracing a design pattern traditionally used by server-side frameworks. This pattern is called Model-View-Controller (MVC), and it is an established pattern that was originally introduced in the 1970s. You should already be familiar with it from the ASP.NET MVC fundamentals, but I will revisit it here for reference.

Note

Technically, AngularJS uses a variant of the MVC, which is closer to the Model-View-ViewModel (MVVM) pattern, but the definition of MVC from the next section still applies to it. One of the core members of the AngularJS team declared the main design pattern behind AngularJS as being "Model-View-Whatever works for you" (MVW or MV*) in this post at http://plus.google.com/+AngularJS/posts/aZNVhj355G2.

The Model-View-Controller pattern

The design pattern is specific for applications with user interfaces and introduces a separation between the following aspects:

  • Model: This is the application data and the business logic associated with it

  • View: This is the output of the application data in any form that can be consumed or manipulated by a user

  • Controller: This is the logic to get data from the View to the Model and back, and to manage any interaction with the View or the Model

The Model does not have direct access to the View or Controller. Any change in the Model gets propagated to the View through notifications or polling by the Controller. This allows the Model to be tested in isolation from the View and Controller. It supports the separation of concerns between application layers, which is essential to support code reusability and scalability. You can reuse the same model to power different views or cache model instances between application data requests.

The Controller can be instantiated without requiring the underlying View infrastructure to be active. This ensures Controller testability, and it hides the specifics of the View infrastructure implementation from the Controller. You can reuse the same Controller to power different Views with a similar structure and functionality or to power Views that differ only through the infrastructure implementation.

I mentioned the Model, View, and Controller concepts in the previous section, and I identified them as follows:

  • Model: This contains the scope properties. Any directive or controller has access to a scope instance.

  • View: This contains the rendered HTML elements that are enhanced or extended by directives.

  • Controller: This is a constructor function that has access to a scope instance and uses it to provide data and functions to the View.

The MVC pattern, as used in AngularJS, allows a great degree of flexibility for the application code. It introduces the reusability of Controllers, Models and, Views; you can have the same Controller reused for multiple Views, the same Model reused in multiple Controllers, and the same View reused for multiple Controllers. It also adds testability for Models, Controllers, and even directives. Understanding how the pattern needs to be used in AngularJS is key to organizing your application code.

If we go back to Example3, we will be able to identify the $scope parameter of the ExampleController function with the Model, the markup delimited by the body element and the ng-controller attribute with the View, and the ExampleController function with the Controller.

The structure of an AngularJS application

The examples from the previous section use an implicit application configuration. There are examples when you need to run some configuration before the application starts, or you need to run multiple AngularJS applications from a single JavaScript code base.

Bootstrapping an AngularJS application

The framework allows for an explicit application initialization, as showcased in the next example. I reduced the first AngularJS example, and it now allows only username editing. I added a new attribute, ng-focus, which is a directive that will evaluate an expression when the input element is focused.

The code executed in the following event will show the previously entered username while the new username is being changed:

<!DOCTYPE html>
<html ng-app="myApp">
<head>
  <meta charset="utf-8" />
  <title>Chapter1 Example4</title>
  <script src="http://code.angularjs.org/1.2.14/angular.js"></script>
</head>
<body ng-controller="ExampleController">
  <h1>Introduction</h1>
  <label>My name:</label>
  <input type="text" placeholder="Please enter name" ng-model="name" ng-focus="onNameFocused()">
  <h3 ng-show="name">Hello! My name is {{name}}.</h3>
  <div ng-show="previousName">Previous name was {{previousName}}.</div>
<script>
  var myAppModule = angular.module('myApp', []);
  myAppModule.controller('ExampleController', function ($scope) {
    $scope.name = "Alex Pop";
    $scope.previousName = "";
    $scope.onNameFocused = function() {
      $scope.previousName = $scope.name;
    };
  });
</script>
</body>
</html>

You can view the example either online at http://plnkr.co/edit/dfJKeNwuRMweGveBhErE or in the Example4 folder from the source code for this chapter.

The first highlighted attribute is ng-app, which has a value this time around. The myApp value represents the unique identifier of the current AngularJS application. The next highlighted code initializes a new AngularJS component called module, which will be used via the myApp identifier to bootstrap the AngularJS application.

A module is a container-like object with a unique identifier that groups together the AngularJS components used to build an application: controllers, directives, and others, such as providers, factories, services, values, constants, animations, and filters. The module has methods that are specific to the AngularJS application components I mentioned. You can see one of these methods in the last highlighted code section in the previous example.

The module controller function takes the controller name and controller constructor function as arguments. The constructor function is similar to the one from Example3, and this time around, it is associated with a specific module rather than being standalone. Throughout this chapter, we will explore other module methods when we introduce AngularJS components.

Defining module dependencies

Modules can be used to share AngularJS components between different applications. A module can reference other modules, as in the following example, showing a different module definition:

var myApp1Module = angular.module('myApp1', ['myApp2', 'myApp3']);

The second parameter of the module definition is the array of module names that the application depends on. The AngularJS framework itself is organized into different modules. The principal AngularJS module is called ng, and it is loaded into every AngularJS application by default. Other AngularJS modules, such as ngResource, that provide functionality for web services have to be explicitly referenced and declared as a dependency of the application. First, you need to reference the JavaScript file that contains the ngResource module as shown in the following code:

<script src="http://code.angularjs.org/1.2.14/angular-resource.js"></script>

Then, you need to declare a dependency on the module for the AngularJS application using the following code:

var myAppModule = angular.module('myApp', ['ngResource']);

A similar procedure has to be implemented if you want to perform the following tasks:

  • Split your application into different modules. By doing so, you can reuse the modules between different AngularJS applications.

  • Reference other AngularJS framework modules such as ngRoute or third-party AngularJS modules such as AngularUI Bootstrap ui.bootstrap.

The module dependency array is another signature of the dependency injection mechanism, explored later in this chapter, where the dependency names are declared, and AngularJS ensures that they are located, initialized, and provided to the application module.

A module has two methods that can be used to perform further configuration and initialization outside of individual AngularJS components. The first method is config, which allows you to perform any additional configuration when the module is loading. The second method is run, which allows you to run custom code after all of the module components are loaded.

 

The JavaScript patterns and practices used in AngularJS applications


At this point, we are almost ready to discuss AngularJS in more detail. However, before doing that, we need to introduce some JavaScript patterns and practices that will be useful in understanding the rest of the content in this chapter.

One of the difficult problems to solve when writing JavaScript code is to avoid the pollution of the global scope. Any variable declared outside of a function body will automatically be visible to the global scope. You can easily imagine a scenario where your variable names clash with the variables defined in other JavaScript files or libraries. Also, JavaScript automatically moves all variable declarations to the top of the current scope. This behavior is called "hoisting" and can lead to scenarios where you use a variable before it is declared, which is confusing and can cause unintended errors.

To avoid these problems, a typical workaround is to use a function body to declare your variables. Variables declared in this way belong to the local scope of the current function, and they are invisible to the global scope. This workaround is based on two patterns used frequently in AngularJS code bases: the Immediately-invoked Function Expression (IIFE)—pronounced "iffy"—and the revealing module pattern.

Immediately-invoked Function Expression

If we append the line, console.log(myAppModule.name); at the end of the script section from the full example of the previous AngularJS application, we will see the name of the module written in the console as myApp. If we convert the example to use an Immediately-invoked Function Expression, the script section will look like the following code:

;(function(){
  var myAppModule = angular.module('myApp', []);
  myAppModule.controller('ExampleController', function ($scope) {
    $scope.name = "Alex Pop";
    $scope.previousName = "";
    $scope.onNameFocused = function() {
      $scope.previousName = $scope.name;
    };
  });
}());
console.log(myAppModule.name);

You can view the preceding example either online at http://plnkr.co/edit/A6XZfvgJITpctLEwmXC7 or in the Example5 folder from the source code for this chapter.

I have highlighted the changes required to convert the code to use the Immediately-invoked Function Expression. The leading semicolon prevents issues caused by the automatic semicolon insertions in JavaScript when your scripts get concatenated with other scripts. The enclosing parentheses after the leading semicolon and before the last semicolon are a convention for these types of expressions.

The example will still work as before, but the console output will have this message: Uncaught ReferenceError: myAppModule is not defined. Using this pattern, we made the application module invisible to the global scope, while leaving it accessible to the AngularJS infrastructure.

The revealing module pattern

The revealing module pattern solves the problem of implementation details being hidden for JavaScript objects that need to provide publicly accessible properties. The following example is a plain JavaScript one—no external library references are required:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title>Chapter1 Example6</title>
</head>
<body>
  <h1>Revealing module pattern</h1>
  <script>
    var revealingModule = (function() {
      var innerObject = 5;
      var innerFunction = function(value) {
        return innerObject + value;
      };
      return {
        outerObject1: innerFunction(1),
        outerObject2: innerFunction(2),
        outerFunction: innerFunction
      };
    }());
    console.log("outerObject1:" + revealingModule.outerObject1);
    console.log("outerObject2:" + revealingModule.outerObject2);
    console.log("innerObject:" + revealingModule.innerObject);
    console.log("outerFunction(3):" + revealingModule.outerFunction(3));
    console.log("innerFunction(3):" + revealingModule.innerFunction(3));
  </script>
</body>
</html>

You can view the example either online at http://plnkr.co/edit/AFbIj5YQO64N9sKYF19u or in the Example6 folder from the source code for this chapter.

I have highlighted the revealing module pattern, and you will notice that it relies on an IIFE to define itself. Using this pattern, all of the variables declared inside of the IIFE are inaccessible to the outside scope, and the only visible properties are the ones returned in the last statement. The console output for this example is the following:

outerObject1:6
outerObject2:7
innerObject:undefined
outerFunction(3):8
Uncaught TypeError: Object #<Object> has no method 'innerFunction'

Any reference to the variables defined within the IIFE will be unsuccessful, even if the property exposed is a direct reference to an inner variable like the outerFunction property. You will see this pattern in action throughout the rest of the examples of this book.

Note

You can find more information about the revealing module pattern and other JavaScript design patterns in the online resource Learning JavaScript Design Patterns, Addy Osmani, O'Reilly Media, available at http://addyosmani.com/resources/essentialjsdesignpatterns/book.

The strict mode of JavaScript

The JavaScript standard ECMAScript 5 has introduced a new way to use a stricter variant of JavaScript. This variant changes the behavior of the JavaScript runtime, and the following are some changes that occur in strict mode:

  • Some silent errors are thrown instead of being ignored, such as assignment to a nonwritable property.

  • All global variables need to be explicitly declared. When you mistype a global variable name, an exception is thrown.

  • All of the property names of an object need to be unique, and all of the parameter names for a function also need to be unique.

By including the line "use strict"; in your scripts, you can adhere to the ECMAScript 5 strict mode when using a modern browser. If the script is loaded in an older browser, the statement is ignored and the JavaScript is parsed in non-strict mode. Strict mode can only be safely declared at the top of a function body. If it is declared in the global scope, it can cause issues when a strict mode script is concatenated with other non-strict scripts.

Using strict mode leads to safer, cleaner code with fewer errors. It is now common practice that any AngularJS script will be enclosed by an IIFE with strict mode enabled.

All AngularJS examples throughout the rest of the book will use the patterns discussed in this section.

 

Dependency injection


When I introduced the controller, I mentioned the fact that the AngularJS infrastructure initializes and loads the $scope object. The controller constructor function that uses the application module is shown in the following code:

var myAppModule = angular.module('myApp', []);
  myAppModule.controller('ExampleController', function ($scope) {
    $scope.name = "Alex Pop";
    $scope.previousName = "";
    $scope.onNameFocused = function() {
      $scope.previousName = $scope.name;
    };
  });

I highlighted the controller constructor function. It has the $scope parameter specified, but it has not been initialized anywhere. You will see this type of function signature a lot for AngularJS controllers and other object definitions. A controller declares its dependencies (such as the $scope parameter) in its constructor function signature, and AngularJS uses a technique called dependency injection to manage and load these dependencies.

Dependency injection is a software design pattern that facilitates the management of code dependencies by delegating them to a dedicated software component known as the injector. Each AngularJS module has an injector instance that deals with resolving controllers and other object dependencies by loading all object definitions before the application starts and injecting them as parameters to constructor functions during application runtime.

In the previous example, the controller definition uses implicit dependency injection. The AngularJS injector looks at the parameter name and infers the required dependency that needs to be resolved, which is the current available $scope instance. However, if your JavaScript code gets minified as part of the build process, the parameter name will be changed and the injector will not be able to infer the correct name. For this scenario, you need to use explicit dependency injection as highlighted in the next example:

var myAppModule = angular.module('myApp', []);
  myAppModule.controller('ExampleController', ['$scope', function ($scope) {
    $scope.name = "Alex Pop";
    $scope.previousName = "";
    $scope.onNameFocused = function() {
      $scope.previousName = $scope.name;
    };

You can view the example either online at http://plnkr.co/edit/rbd1GjPEK1OGrnPGFsjg or in the Example7 folder from the source code for this chapter.

The constructor function was replaced with an array that contains the dependency names with the constructor function as the last element. It is good practice to use explicit dependency injection, and we will use it throughout the rest of the AngularJS examples in this book.

 

Introducing AngularJS services


Until this point, we have discussed some of the core concepts of the AngularJS architecture. The content we covered so far should be a good starter for very small applications or other scenarios where we just need to use out of the box AngularJS directives and other built-in components.

For other types of applications or more advanced usage scenarios, we will sometimes need to reuse code or share data between two or more controllers. Let's take the previous AngularJS example and change it from a user introduction screen to a game setup screen. The screen will now allow the editing of two player names while keeping track of the previous names. To provide this functionality, I have created two separate controllers, each one with access to its own scope instance. The following code is the content of the body element:

  <h1>Game setup</h1>
  <div ng-controller="ExampleController1">
    <h2>Player 1</h2>
    <label>Name:</label>
    <input type="text" placeholder="Please enter player 1 name" ng-model="name" ng-focus="onNameFocused()">
    <h3 ng-show="name">Player 1 name is {{name}}.</h3>
    <h3 ng-show="previousName">Previous Player 1 name was {{previousName}}.</h3>
  </div>
  <div ng-controller="ExampleController2">
    <h2>Player 2</h2>
    <label>Name:</label>
    <input type="text" placeholder="Please enter player 2 name" ng-model="name" ng-focus="onNameFocused()">
    <h3 ng-show="name">Player 2 name is {{name}}.</h3>
    <h3 ng-show="previousName">Previous Player 2 name was {{previousName}}.</h3>
  </div>
<script>
 (function(){
  "use strict";
  var myAppModule = angular.module('myApp', []);
  myAppModule.controller('ExampleController1', ['$scope', function ($scope) {
    $scope.name = "Player1";
    $scope.previousName = "";
    $scope.onNameFocused = function() {
      $scope.previousName = $scope.name;
    };
  }]);
  myAppModule.controller('ExampleController2', ['$scope', function ($scope) {
    $scope.name = "Player2";
    $scope.previousName = "";
    $scope.onNameFocused = function() {
      $scope.previousName = $scope.name;
    };
  }]);
}());
</script>

You can view the example either online at http://plnkr.co/edit/e8oWZu68tMwsGAbHDUEN or in the Example8 folder from the source code for this chapter.

I have highlighted the directives that associate the two controllers with HTML elements. The code of the two controllers is almost identical, with the exception of the initial player name value. It looks like unnecessary code duplication, but fortunately, AngularJS has a built-in component that allows us to refactor and reuse this code. This built-in component is called a service, and it is defined using a syntax similar to a controller definition.

Usually, we register a service with an AngularJS application module that uses a service factory function. This function will be called by AngularJS to create the service instance that will be used throughout the AngularJS application. This service instance will be injected in all AngularJS components that declare a dependency on the particular service. The following example uses a service factory function to define a service that encapsulates the code shared between the controllers from the previous example. The following code is the content of the body element with the HTML markup placed first:

  <h1>Game setup</h1>
  <div ng-controller="ExampleController1">
    <h2>Player 1</h2>
    <label>Name:</label>
    <input type="text" placeholder="Please enter player 1 name" ng-model="player.name" ng-focus="player.onNameFocused()">
    <h3 ng-show="player.name">Player 1 name is {{player.name}}.</h3>
    <h3 ng-show="player.previousName">Previous Player 1 name was {{player.previousName}}.</h3>
  </div>
  <div ng-controller="ExampleController2">
    <h2>Player 2</h2>
    <label>Name:</label>
    <input type="text" placeholder="Please enter player 2 name" ng-model="player.name" ng-focus="player.onNameFocused()">
    <h3 ng-show="player.name">Player 2 name is {{player.name}}.</h3>
    <h3 ng-show="player.previousName">Previous Player 2 name was {{player.previousName}}.</h3>
    <h3>Player count across all service instances is {{playerCount}}.</h3>
  </div>

The markup now references the $scope data model through a new player object as highlighted in the HTML for Player 1. Let's take a look at the script section, where I have highlighted the new service definition in the following code:

  <script>
    (function() {
      "use strict";
      var myAppModule = angular.module('myApp', []);
      myAppModule.factory('playerService', function() {
        var playerCount = 0;
        var createDefaultPlayer = function() {
          playerCount += 1;
          var player = {
            name: "",
            previousName: ""
          };
          player.onNameFocused = function() {
            player.previousName = player.name;
          };
          return player;
        };
        return {
          createPlayer: function(name) {
            var player = createDefaultPlayer();
            player.name = name;
            return player;
          },
          getPlayerCount: function() {
            return playerCount;
          }
        };
      });
      myAppModule.controller('ExampleController1', ['$scope', 'playerService',
        function($scope, playerService) {
          $scope.player = playerService.createPlayer('Player1');
        }
      ]);
      myAppModule.controller('ExampleController2', ['$scope', 'playerService',
        function($scope, playerService) {
          $scope.player = playerService.createPlayer('Player2');
          $scope.playerCount = playerService.getPlayerCount();
        }
      ]);
    }());
  </script>

You can view the example either online at http://plnkr.co/edit/OOocE8UUg1NWZLHidjmt or in the Example9 folder from the source code for this chapter.

The first highlighted snippet is the service definition that looks similar to a controller definition, with the exception that it returns an object that represents the service factory. This object is used to create the service instance that will be injected in all of the AngularJS components that have this service declared as a dependency.

In the new service, we transformed the previous controller code into a function called createDefaultPlayer(), which will create a new object that represents a player. The service instance has a method to create a new player with a predefined name called createPlayer(name). The service factory function will keep track of how many player objects were created using the playerCount variable. The variable will be returned by the service instance function, getPlayerCount(). On a side note, you can see the revealing module pattern in action here. Although the script section is now bigger, we obtained new features such as code reusability and flexibility to provide more complex functionality than before.

There are other methods available on the module interface to declare an AngularJS service, such as service, value, and constant. The service method will use a constructor function to create the service instance, while the value method will use an already created service instance that will be passed unchanged to the AngularJS injector. The constant method is similar with the value method, with the difference that it will be available during the configuration phase of the application module. The factory method is one of the most flexible methods, and it will be the most frequently used method in the rest of the examples from this book. It allows additional configuration to the returned service instance, and you can even keep track of data outside of the service instance, such as with the playerCount variable from the previous example.

All service definition methods are, in fact, helpers of a more generic module method called provider. The method is a constructor function that creates an object that has to implement a $get method. The $get method returns a service factory function that will be used to create service instances by the injector. Usually, you need to use the provider method only when you need different configuration options for services reused across more than one application module. All service definition methods are ultimately resolved as provider methods by AngularJS. There is a $provide service that manages all objects created by this method, and these objects are called service providers. The $injector service uses the service providers to get the service instances that it needs to inject throughout an application module. You can get more information on service providers at http://code.angularjs.org/1.2.15/docs/guide/providers.

At this point, you will notice a naming convention among the service names prefixed with the $ symbol. This is an AngularJS-specific convention, where all of the services and special objects that belong to its infrastructure will be prefixed with the $ symbol. This helps developers identify their own services and components from AngularJS ones. It is worth mentioning that services can have dependencies on other services that are either built-in or custom, such as the one in the previous example.

The second highlighted code section is the new constructor function signature for the first controller. You will notice that we can now reference the new service alongside the $scope parameter using the explicit dependency injection notation. Both controllers are now using the same service instance. The last controller even displays the count of the player instances created by the service.

 

Directives


One of the most important features of AngularJS is that it has majorly improved the HTML authoring story. It has extended the HTML vocabulary through directives, enabling a declarative style of defining the user interface. You can use its powerful, built-in directives and easily define new ones.

We have used a lot of directives in the examples presented so far, and most of them used the ng- prefix. When you take a look at the directives' documentation pages at http://code.angularjs.org/1.2.15/docs/api, you will notice that the directive names appear slightly different—ng-app is ngApp and ng-controller is ngController. AngularJS removes any data- or x- prefixes from the HTML markup and converts the -, _, and : characters to a camel case directive name. From now on, we will refer to different directives using the names from the AngularJS documentation.

The ngRepeat directive

Next, we will explore some important built-in directives and see how to build custom directives. Looking back at the previous example, the HTML markup seems to have been duplicated for the two players. There is a built-in directive called ngRepeat that allows us to remove the duplicated markup as highlighted in the next example. The following code is the inclusive content of the body element without the script element:

<body ng-controller="ExampleController">
  <h1>Game setup</h1>
  <div ng-repeat="player in players">
    <h2>Player {{$index + 1}}</h2>
    <label>Name:</label>
    <input type="text" placeholder="Please enter player {{$index + 1}} name" ng-model="player.name" ng-focus="player.onNameFocused()">
    <h3 ng-show="player.name">Player {{$index + 1}} name is {{player.name}}.</h3>
    <h3 ng-show="player.previousName">Previous Player {{$index + 1}} name was {{player.previousName}}.</h3>
  </div>
</body>

You can view the example either online at http://plnkr.co/edit/4tVY2Li9DjIg8LBqL3nK or in the Example10 folder from the source code for this chapter.

The ngRepeat directive works with a collection of objects and repeats an HTML markup section for each item in the collection. We created an array of player items in the controller that is used in the ngRepeat directive. The first highlighted code section shows the expression used to iterate through the collection, and the div element that has the directive is repeated for each item in the collection. The player variable defined in the ngRepeat expression is only available inside of the directive. The ngRepeat directive has its own scope that contains other directive-specific variables such as $index, which has been used in the next highlighted code snippet. This variable of the type number keeps track of the current collection item index, and there are other directive-specific Boolean variables available: $first, $middle, $last, $odd, and $even.

The example works for HTML markup that repeats a single element. When the HTML markup that needs repeated elements has separate start and end elements, you need to use two different directive attributes. The first is ng-repeat-start, which is a renamed ng-repeat directive that needs to be used on the start HTML element. The second is ng-repeat-end, which does not have an expression value and is used on the HTML element that ends the markup that needs repeated elements. The previous example of the body element content can now be written using the h2 element as the start of the repeated markup and the h3 element as the end, as shown in the following code:

<h1>Game setup</h1>
  <div>
    <h2 ng-repeat-start="player in players">Player {{$index + 1}}</h2>
    <label>Name:</label>
    <input type="text" placeholder="Please enter player {{$index + 1}} name" ng-model="player.name" ng-focus="player.onNameFocused()">
    <h3 ng-show="player.name">Player {{$index + 1}} name is {{player.name}}.</h3>
    <h3 ng-repeat-end ng-show="player.previousName">Previous Player {{$index + 1}} name was {{player.previousName}}.</h3>
  </div>

You can view the example either online at http://plnkr.co/edit/Z2faLKy0e0PF7Lx9liEW or in the Example11 folder from the source code for this chapter.

The ngInclude directive

The ngRepeat directive example is very useful when we need to manipulate the HTML for a specific application view. However, I can easily imagine scenarios where the HTML for a player has to be reused between different views. If there is a single player game, we want to see only one player editing form rather than two. AngularJS offers a simple but powerful solution through the ngInclude directive. This directive allows the referencing of a separate file that will be loaded and rendered in the current HTML view by AngularJS.

To introduce this directive, I had to change the HTML for the ngRepeat example and add a new file that contains the player HTML markup. The following code is the new HTML for the original body element:

<body ng-controller="ExampleController">
  <h1>Game setup</h1>
  <div ng-repeat="player in players" ng-init="playerIndex = $index">
    <ng-include src="'player.html'"></ng-include>
  </div>
</body>

The following code represents the new player.html file:

<h2>Player {{playerIndex + 1}}</h2>
<label>Name:</label>
<input type="text" placeholder="Please enter player {{playerIndex + 1}} name" ng-model="player.name" ng-focus="player.onNameFocused()">
<h3 ng-show="player.name">Player {{playerIndex + 1}} name is {{player.name}}.</h3>
<h3 ng-show="player.previousName">Previous Player {{playerIndex + 1}} name was {{player.previousName}}.</h3>

You can view the example either online at http://plnkr.co/edit/phaxRDtE8CM2EMdzc83L or in the Example12 folder from the source code for this chapter.

The first highlighted attribute is a new directive, ngInit, that evaluates an arbitrary expression. Although this directive can be used anywhere, it is best practice to only use it in the context of the ngRepeat directive. We use it to create a new scope property that is an alias of the $index variable from the ngRepeat directive. The reason behind this alias is to allow the reuse of the player markup in contexts where there is no enclosing ngRepeat directive.

The next highlighted element is the ngInclude directive, which fetches the referenced player.html file, renders it, and creates a new scope for it. The scope inherits the current ngRepeat iteration scope and its player and playerIndex properties. The last highlighted expression shows how the property created by ngInit is used in player markup.

Creating a custom directive

While the ngInclude directive is powerful and simple, AngularJS provides another way to create reusable components. It allows you to create your own directive and use it just like any other built-in directive. The result is a more expressive HTML markup and a new component that can be used for more advanced data binding scenarios. A custom directive is also the only place where it is recommended to directly manipulate HTML elements. A controller or a service should not have any code that manipulates the DOM; this kind of code belongs to a directive.

I will start first by simplifying the previous example. The script section has a simpler service, with the playerIndex variable moved to a new property of the player object. The player.html file has some markup removed, and it will rely only on the properties of the player object.

The following code is the new main file listing for the body element:

<body ng-controller="ExampleController">
  <h1>Game setup</h1>
  <div ng-repeat="player in players">
    <my-player />
  </div>
  <script>
  (function() {
    "use strict";
    var myAppModule = angular.module('myApp', []);
    myAppModule.factory('playerService', function() {
      var playerIndex = 0;
      return {
        createPlayer: function() {
          playerIndex += 1;
          return {
            id: playerIndex,
            name: "Player" + playerIndex
          };
        }
      };
    });
    myAppModule.controller('ExampleController', ['$scope', 'playerService',
      function($scope, playerService) {
        $scope.players = [playerService.createPlayer(), playerService.createPlayer()];
      }
    ]);
    myAppModule.directive('myPlayer', function() {
      return {
        restrict: 'E',
        templateUrl: 'player.html'
      };
    });
  }());
</script>
</body>

The following code represents the updated player.html file:

<h2>Player {{player.id}}</h2>
<label>Name:</label>
<input type="text" placeholder="Please enter player {{player.id}} name" ng-model="player.name">
<h3 ng-show="player.name">Player {{player.id}} name is {{player.name}}.</h3>

You can view the example either online at http://plnkr.co/edit/lKcu3MZDeKGrV7ITRUZT or in the Example13 folder from the source code for this chapter.

The first highlighted element is the new custom directive, and you can view its definition at the end of the script section in the last highlighted snippet. The directive definition is a factory function that, in this scenario, returns an object with specific properties, such as restrict and templateUrl. The restrict property value ensures that the directive is applied only to HTML elements. It can take other values such as A to match an attribute name or C to match a CSS class name, or it can take a combination such as AE. If we don't set the property, it will take the default value, A. The templateUrl property provides the link to the HTML markup that will be rendered for the directive. The directive name follows the convention mentioned a while ago, where the camel case directive name becomes a hyphenated directive name in the HTML markup.

This directive does not create a scope and uses the parent scope provided by the ngRepeat directive. However, you might have a situation where you don't want to give the custom directive unrestricted access to the parent scope. In this case, you can ensure that the directive creates an isolated scope that will need to explicitly be initialized with a parent scope property. The custom directive definition is now as shown in the following code:

myAppModule.directive('myPlayer', function() {
        return {
          restrict: 'E',
          templateUrl: 'player.html',
          scope: {
            player: "=data"
          }
        };
      });

The body element content has been changed to the following code:

<h1>Game setup</h1>
  <div ng-repeat="currentPlayer in players">
    <my-player data="currentPlayer"/>
  </div>

You can view the example either online at http://plnkr.co/edit/gUanL3Fooh8EDzh5ZfWY or in the Example14 folder from the source code for this chapter.

The directive definition has a new property, scope, in the first highlighted section. Since the property value is an object literal, it creates an isolated scope that defines data bindings between the directive scope properties and directive attributes. The last highlighted snippet shows how the player directive scope property is mapped through the data directive attribute value to the ngRepeat scope property, currentPlayer.

The = value from the directive scope definition means that the data binding is a two-way binding, and data changes will be propagated between the directive scope and parent scope. To set up one way data binding between the parent scope and directive scope, you need to replace = with @, and to bind to a parent scope function, you need to use the & symbol. In addition, if the directive attribute name needs to be the same as the directive scope property, the scope definition will turn out like the following code:

scope: {
   player: "="
}

The new directive markup needs to be changed to the following line of code:

<my-player player="currentPlayer"/>

You can view the example either online at http://plnkr.co/edit/xPSGH92fhmTHaZS5HkcT or in the Example15 folder from the source code for this chapter.

The examples showcased here introduce a simpler way to create custom directives that are more powerful than ngInclude.

Note

There is a lot more to explore about custom directives, especially about manipulating DOM elements, but it is beyond the scope of this book. You can find more information on creating directives at http://code.angularjs.org/1.2.15/docs/guide/directive.

 

Filters


Other significant components of AngularJS are filters that allow us to format an AngularJS expression in the HTML markup in a declarative way. I have altered the first AngularJS example to use two built-in filters, as shown in the following code:

<body ng-controller="ExampleController">
  <h1>Introduction</h1>
  <label>My name:</label>
  <input type="text" placeholder="Please enter name" ng-model="name">
  <h3 ng-show="name">Hello! My name is {{name | uppercase}} and today is {{today | date:'EEEE'}}.</h3>
  <script>
  var myAppModule = angular.module('myApp', []);
  myAppModule.controller('ExampleController', function ($scope) {
    $scope.name = "Alex Pop";
    $scope.today = new Date();
  });
  console.log(myAppModule.name);
</script>
</body>

You can view the example either online at http://plnkr.co/edit/BDPGluxbcNtVpdCNbyil or in the Example16 folder from the source code for this chapter.

Filters are applied to expressions using the | symbol, also known as the pipe operator. The first highlighted filter converts any string character from the left-hand expression to its uppercase value. The second highlighted filter formats an expression that is a date value to a specific display. We chose the day of the week here, but there are a lot of other date formats available.

You can also call the filters in the code as shown in the next example:

<body ng-controller="ExampleController">
  <h1>Introduction</h1>
  <label>My name:</label>
  <input type="text" placeholder="Please enter name" ng-model="name">
  <h3 ng-show="name">Hello! My name is {{getNameWithFilter()}} and today is {{today}}.</h3>
  <script>
  var myAppModule = angular.module('myApp', []);
  myAppModule.controller('ExampleController', function ($scope, $filter) {
    $scope.name = "Alex Pop";
    $scope.getNameWithFilter = function(){
      return $filter('uppercase')($scope.name);
    };
    $scope.today = $filter('date')(new Date(),'EEEE');
  });
  console.log(myAppModule.name);
</script>
</body>

You can view the example either online at http://plnkr.co/edit/mb11KyG9Q1tDmDVHiYwp or in the Example17 folder from the source code for this chapter. Note that we had to inject the $filter service as a dependency to be able to directly use the filter in the controller.

There are other built-in filters that can be explored at http://code.angularjs.org/1.2.15/docs/api/ng/filter, and you can also create your own custom filters. The following code snippet shows the method that the application module provides to define a custom filter:

<body ng-controller="ExampleController">
  <h1>Introduction</h1>
  <label>My name:</label>
  <input type="text" placeholder="Please enter name" ng-model="name">
  <h3 ng-show="name">Hello! My name is {{name | customname}}.<h3>
  <script>
  var myAppModule = angular.module('myApp', []);
  myAppModule.filter('customname', function () {
    return function(name) {
      name = name || '';
      var customName = "";
      for (var i = 0; i < name.length; i++) {
        if(name.charAt(i) == "e") {
          customName += "3";
        }
        else if(name.charAt(i) == "o") {
          customName += "0";
        }
        else {
          customName += name.charAt(i);
        }
      }
      return customName;
    };
  });
  myAppModule.controller('ExampleController', function ($scope) {
    $scope.name = "Alex Pop";
  });
  console.log(myAppModule.name);
</script>
</body>

You can view the example either online at http://plnkr.co/edit/KPrHjnui6t65XqxWVNQE or in the Example18 folder from the source code for this chapter. The first highlighted snippet is the new filter used in the HTML markup. The next highlighted snippet is the filter definition; it returns a function that will convert a string value to a new value, where characters such as e and o are replaced with numbers.

 

Summary


This chapter introduced us to the fundamentals of AngularJS using a series of evolving examples for core concepts such as scopes, directives, data binding, and controllers. We then explored the AngularJS architecture, followed by topics such as JavaScript patterns, dependency injection, and services. The chapter ended with a presentation on directives and filters.

In the next chapter, we will explore the steps required to build AngularJS applications in Visual Studio.

About the Author

  • Alex Pop

    Alex Pop is a professional software developer with 14 years of experience in building applications for various platforms and technologies.

    He has worked for ISVs, building enterprise resource planning applications, a content management system, and insurance and financial software products, and is currently working in the higher education sector as a web application developer.

    He is the author of Learning AngularJS for .NET Developers, Packt Publishing. His developer blog at http://alexvpop.blogspot.co.uk/ contains technical articles about .NET, JavaScript, and various software engineering topics.

    Browse publications by this author

Latest Reviews

(2 reviews total)
Excellent book. Thank you.
Good
Book Title
Unlock this book and the full library for FREE
Start free trial