Starting with AngularJS

We've got most of the pieces of our application stack in place now. We have a runtime environment, Node.js. We've installed and set up a web application framework, Express. We just set up our database, MongoDB.

The one piece that's missing is pretty crucial in any SPA—no matter what the backend stack looks like, there's a frontend framework to make the SPA magic happen.

There are numerous frontend libraries and frameworks used for SPAs, but one of the most popular, and the A in MEAN, is AngularJS, otherwise known as Angular.

Angular is an open source frontend framework, particularly well-suited to building SPA. It's extremely popular and currently maintained by Google.

Note

In this book, we will use AngularJS version 1.4.8, which was released in November, 2015. AngularJS 2.0 was announced in 2014 and is, at the time of publication, just made available in a production version. The 2.0 version introduced breaking non-backward-compatible changes. Most development today is done using some version on the 1.x branch, and the plan is to continue support for the foreseeable future.

Installing AngularJS into the application

Ultimately, Angular is a single JavaScript file with some optional plugin files. There are a few ways to add Angular to your frontend application. You can download the package you're interested in or load it with a tool such as Bower.

The simplest way for us to get started is to simply point to the Angular file on a publicly available CDN. We can include Angular 1.4.8 from https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.js.

Let's open our index.ejs file and include a script tag linking to the following file:

<!DOCTYPE html> 
<html> 
  <head> 
    <title><%= title %></title> 
    <link rel='stylesheet' href='/stylesheets/style.css' /> 
  </head> 
  <body> 
    <h1><%= title %></h1> 
    <p>Welcome to <%= title %></p> 
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.js"></script> 
  </body> 
</html> 

Tip

It's good practice, when possible, to include script tags linking to external JavaScript files right before the closing body tag in HTML. This is done for performance reasons. You can find out more and see some examples showcasing the reasoning for this at http://stevesouders.com/hpws/rule-js-bottom.php.

If you restart the server and load the default page at localhost:3000, you won't see very much. You are loading AngularJS, but there's no visible effect yet. We will build up some example frontend code in layers.

The first thing we want to do after adding the AngularJS script is to change the html tag to read as shown in the following code:

<html ng-app> 

The ng-app attribute on the head element is what is called an Angular directive. When Angular loads in a page, it goes through a bootstrapping phase looking for directives such as ng-app. This directive tells Angular where the root element of the application is.

You can think of this attribute as a way of marking out an area of interest that Angular will manage. In our case, we'd like to use Angular components on the whole page, so we'll declare the HTML element as the root element.

In the next section, we will build a module that will become our root application.

Building the first AngularJS module

AngularJS was designed to be modular and includes a function to register modules. Modules act as containers for other objects, such as Angular services, directives, and controllers.

Angular modules are also injectable. This means that modules can be injected into and consumed by other modules. Angular has a unique dependency injection system, which we will see shortly and use a lot.

Create a new JavaScript file in the public/javavscripts directory of giftapp called app.js and type the following code into it:

var giftAppModule = angular.module('giftAppModule', []); 
 
giftAppModule.value('appName', 'GiftApp'); 

The first line creates and registers an Angular module using the angular.module() function. The first argument to this function is a string that Angular will use as the name of the module, giftAppModule. The second argument is an array of dependencies we wish to inject into this module. For now, we don't have any, so the array is empty.

We then assign the module to the giftAppModule variable. This variable name, even though it happens to be identical to the module name, is unrelated; we could have called it anything else. You don't have to assign a module to a variable name, but it's useful as it allows us to more cleanly add assets to the module.

The next line, giftAppModule.value('appName','GiftApp');, creates a new service on the module by calling the value function. A service in Angular is a singleton, which is injectable. Angular includes a number of types of services. A value service is the simplest type and creates a name value pair that can be injected and used. We will use this in our controller.

Finally, we want to load our new module and Bootstrap it as the root Angular application in our index.ejs template.

Take a look at the following code:

<!DOCTYPE html> 
<html ng-app="giftAppModule"> 
  <head> 
    <title><%= title %></title> 
    <link rel='stylesheet' href='/stylesheets/style.css' /> 
  </head> 
  <body> 
    <h1><%= title %></h1> 
    <p>Welcome to <%= title %></p> 
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.js"></script> 
    <script src="/javascripts/app.js"></script> 
  </body> 
</html> 

There are two important changes to note here. First, in the HTML element we added a reference to the giftAppModule we just created by setting it as the value of the ng-app directive. The next change is that we've added a new script tag before the closing body tag that loads the app.js file that we just created.

Load order is important here, and Angular must be loaded before app.js or it will fail. Note the path that we're using to load app.js: /javascripts/app.js. This works because of piece of code in the Express app.js that points requests for static files at the public directory, app.use(express.static(path.join(__dirname,'public')));.

Starting the server up, if it's stopped, and reloading the page does nothing visible at this point. To start making changes to the page, we need to add a controller and an Angular expression.

Adding a controller

In Angular, a controller is a JavaScript object that exposes data and functionality to the view. It does this through Angular's $scope object.

Open your app.js file and add the following code:

var giftAppModule = angular.module('giftAppModule', []); 
 
giftAppModule.value('appName', 'GiftApp'); 
 
giftAppModule.controller("GreetingController", ['$scope','appName', function($scope)
{

        $scope.name = appName;

        $scope.greeting = "Hello Angular"

    }
]

);

The additional code has created a controller constructor on giftAppModule called GreetingController. This isn't an actual controller until it is invoked in the page using the ng-controller directive.

The first argument to the function is the name of the controller. The second argument is an array consisting of the dependencies we wish to inject. The final item in the array is the function itself. Angular documentation refers to this as array annotation and it is the preferred method of creating constructors.

The module name strings of the first part of the array map to the arguments of the function. The order of each must be the same.

Next, we will need to add the controller to our index.ejs html, as follows:

<!DOCTYPE html> 
<html ng-app="giftAppModule"> 
  <head> 
    <title><%= title %></title> 
    <link rel='stylesheet' href='/stylesheets/style.css' /> 
  </head> 
  <body> 
    <h1><%= title %></h1> 
    <p>Welcome to <%= title %></p> 
    <div ng-controller="GreetingController"> 
 
    </div> 
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.js"></script> 
    <script src="/javascripts/app.js"></script> 
  </body> 
</html> 

Here, we will add a div tag and give it an ng-controller attribute with a value of GreetingController. When we load this page, Angular will create a new GreetingController object and attach a child scope to this part of the page.

Again, if you hit reload on your browser, you will not see anything different. Generally, to display data to the user, you will use Angular expressions.

Displaying data with Angular expressions

Angular expressions are code snippets that are placed between double curly braces ({{}}). Angular evaluates these (the JavaScript eval() function is not used as it's not a safe mechanism).

The Angular documentation refers to expressions as JavaScript as there are some pretty major differences. For example, Angular expressions don't have control loops.

Angular expressions are evaluated within the context of the current scope.

Let's make the following changes to index.ejs:

<!DOCTYPE html> 
<html ng-app="giftAppModule"> 
  <head> 
    <title><%= title %></title> 
    <link rel='stylesheet' href='/stylesheets/style.css' /> 
  </head> 
  <body> 
    <h1><%= title %></h1> 
    <p>Welcome to <%= title %></p> 
    <div ng-controller="GreetingController"> 
       {{ greeting }} from {{ name }} {{ 2+3 }} 
    </div> 
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.js"></script> 
    <script src="/javascripts/app.js"></script> 
  </body> 
</html> 

We've added some Angular expressions inside div, where we invoked GreetingController. Angular makes the GreetingController scope object available inside this div.

Now, if you reload this page, under Welcome to Express, you should see the following line of code:

Hello Angular from GiftApp 5 

Angular has evaluated the expressions and displayed them as strings. The expressions containing greeting and name are pulling those values from the scope. The final expression is just doing a little bit of arithmetic.

Two-way data binding

One of the main features that Angular provides is called two-way data binding. This means that changing data in the view updates the data on the model. Likewise, data changed in the model is reflected in the view.

Open app.js and add the following property to the scope:

var giftAppModule = angular.module('giftAppModule', []); 
 
giftAppModule.value('appName', 'GiftApp'); 
 
giftAppModule.controller("GreetingController", ['$scope','appName', function($scope, appName){ 
        $scope.name = appName; 
        $scope.greeting = "Hello Angular"; 
        $scope.newName = "Bob"; 
    }] 
); 

We've added a newName property and assigned to it the string, Bob.

Now, we will need to make the following changes to index.ejs:

<!DOCTYPE html> 
<html ng-app="giftAppModule"> 
  <head> 
    <title><%= title %></title> 
    <link rel='stylesheet' href='/stylesheets/style.css' /> 
  </head> 
  <body> 
    <h1><%= title %></h1> 
    <p>Welcome to <%= title %></p> 
    <div ng-controller="GreetingController"> 
       {{ greeting }} from {{ name }} {{ 2+3 }} {{ newName }} 
        <p><input type=""text" ng-model="newName"></p> 
    </div> 
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.js"></script> 
    <script src="/javascripts/app.js"></script> 
  </body> 
</html> 

We've made two changes to this file. The first is that we've added the {{newName}} expression after the arithmetic expression. This renders the Bob string to the screen. The second change is that we've added a text input control and added the ng-model="newName" directive. This directive binds the value in the text box to the newName property on the scope.

When the page loads, the value in the text box is Bob. But what happens if we type something besides Bob in the text box? The value rendered by the expression changes nearly instantly.

This is a clear example of what is meant by two-way data binding. Changes to the data in the view affect the model seamlessly.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.113.55