Chapter 1. Introduction to AngularJS

Google’s AngularJS is an all-inclusive JavaScript model-view-controller (MVC) framework that makes it very easy to quickly build applications that run well on any desktop or mobile platform. In a very short period of time, AngularJS has moved from being an unknown open source offering to one of the best known and most widely used JavaScript client-side frameworks offered. AngularJS 1.3 and greater combined with jQuery and Twitter Bootstrap give you everything you need to rapidly build HTML5 JavaScript application frontends that use REST web services for the backend processes. This book will show you how to use all three frontend components to harness the power of REST services on the backend and quickly build powerful mobile and desktop applications.

JavaScript Client-Side Frameworks

JavaScript client-side applications run on the user’s device or PC, and therefore shift the workload to the user’s hardware and away from the server. Until fairly recently, server-side web MVC frameworks like Struts, Spring MVC, and ASP.NET were the frameworks of choice for most web-based software development projects. JavaScript client-side frameworks, however, are sustainable models that offer many advantages over conventional web frameworks, such as simplicity, rapid development, speed of operation, testability, and the ability to package the entire application and deploy it to all mobile devices and the Web with relative ease. You can build your application one time and deploy and run it anywhere, on any platform, with no modifications. That’s powerful.

AngularJS makes that process even faster and easier. It helps you build frontend applications in days rather than months and has complete support for unit testing to help reduce quality assurance (QA) time. AngularJS has a rich set of user documentation and great community support to help answer questions during your development process. Models and views in AngularJS are much simpler than what you find in most JavaScript client-side frameworks. Controllers, often missing in other JavaScript client-side frameworks, are key functional components in AngularJS.

Figure 1-1 shows a diagram of an AngularJS application and all related MVC components. Once the AngularJS application is launched, the model, view, controller, and all HTML documents are loaded on the user’s mobile or desktop device and run entirely on the user’s hardware. As you can see, calls are made to the backend REST services, where all business logic and business processes are located. The backend REST services can be located on a private web server or in the cloud (which is most often the case). Cloud REST services can scale from a handful of users to millions of users with relative ease.

Alt Text
Figure 1-1. Diagram of an AngularJS MVC application

Single-Page Applications

AngularJS is most often used to build applications that conform to the single-page application (SPA) concept. SPAs are applications that have one entry point HTML page; all the application content is dynamically added to and removed from that one page. You can see the entry point of our SPA in the index.html code that follows. The tag <div ng-view></div> is where all dynamic content is inserted into index.html:

<!-- chapter1/index.html -->
<!DOCTYPE html>

<html lang="en" ng-app="helloWorldApp">

<head>

<title>AngularJS Hello World</title>

<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">


<script src="js/libs/angular.min.js"></script>
<script src="js/libs/angular-route.min.js"></script>
<script src="js/libs/angular-resource.min.js"></script>
<script src="js/libs/angular-cookies.min.js"></script>


<script src="js/app.js"></script>
<script src="js/controllers.js"></script>
<script src="js/services.js"></script>


</head>

<body>
<div ng-view></div>
</body>

</html>

As the user clicks on links in the application, existing content attached to the tag is removed and new dynamic content is then attached to the same tag. Rather than the user waiting for a new page to load, new content is dynamically displayed in a fraction of the time that it would take to load a new HTML web page.

Tip

You can download the source for the Chapter 1 “Hello, World” application from GitHub.

Bootstrapping the Application

Bootstrapping AngularJS is the process of loading AngularJS when an application first starts. Loading the AngularJS libraries in a page will start the bootstrap process. The index.html file is analyzed, and the parser looks for the ng-app tag. The line <html lang="en" ng-app="helloWorldApp"></html> shows how ng-app is defined. The following code shows the JavaScript that is fired by that line in the index.html file. As you can see, app.js is where the AngularJS application helloWorldApp is defined as an AngularJS module, and this is the entry point into the application. The variable helloWorldApp in this file could be named anything. I will, however, call it helloWorldApp for the sake of uniformity:

/* chapter1/app.js excerpt */
'use strict';
/* App Module */

var helloWorldApp = angular.module('helloWorldApp', [
  'ngRoute',
  'helloWorldControllers'
]);

Dependency Injection

Dependency injection (DI) is a design pattern where dependencies are defined in an application as part of the configuration. Dependency injection helps you avoid having to manually create application dependencies. AngularJS uses dependency injection to load module dependencies when an application first starts. The app.js code in the previous section shows how AngularJS dependencies are defined.

As you can see, two dependencies are defined as needed by the helloWorldApp application at startup. The dependencies are defined in an array in the module definition. The first dependency is the AngularJS ngRoute module, which provides routing to the application. The second dependency is our controller module, helloWorldControllers. We will cover controllers in depth later, but for now just understand that controllers are needed by our applications at startup time.

Dependency injection is not a new concept. It was introduced over 10 years ago and has been used consistently in various application frameworks; DI was at the core of the popular Spring framework written in Java. One of its main advantages is that it reduces the need for boilerplate code, writing of which would normally be a time-consuming process for a development team.

Dependency injection also helps to make an application more testable. That is one of the main advantages of using AngularJS to build JavaScript applications. AngularJS applications are much easier to test than applications written with most JavaScript frameworks. In fact, there is a test framework that has been specifically written to make testing AngularJS applications easy. We will talk more about testing at the end of this chapter.

AngularJS Routes

AngularJS routes are defined through the $routeProvider API. Routes are dependent on the ngRoute module, and that’s why it is a requirement when the application starts. The following code from app.js shows how we define routes in an AngularJS application. Two routes are defined—the first is / and the second is /show:

/* chapter1/app.js excerpt */
helloWorldApp.config(['$routeProvider', '$locationProvider', 
function($routeProvider, $locationProvider){ 
 $routeProvider. 
   when('/', { 
     templateUrl: 'partials/main.html', 
     controller: 'MainCtrl' }).
   when('/show', { 
     templateUrl: 'partials/show.html', 
     controller: 'ShowCtrl' 
}); 

The two defined routes map directly to URLs defined in the application. If a user clicks on a link in the application specified as www.someDomainName/show, the /show route will be followed and the content associated with that URL will be displayed. If the user clicks on a link specified as www.someDomainName/, the / route will be followed and that content will be displayed.

HTML5 Mode

The complete app.js file is shown next. The last line in app.js ($locationProvider.html5Mode(false).hashPrefix('!');) uses the locationProvider service. This line of code turns off the HTML5 mode and turns on the hashbang mode of AngularJS. If you were to turn on HTML5 mode instead by passing true, the application would use the HTML5 History API. HTML5 mode also gives the application pretty URLs like /someAppName/blogPost/5 instead of the standard AngularJS URLs like /someAppName/#!/blogPost/5 that use the #!, known as the hashbang.

/* chapter1/app.js complete file */

'use strict';
/* App Module */

var helloWorldApp = angular.module('helloWorldApp', [
  'ngRoute',
  'helloWorldControllers'
]);

helloWorldApp.config(['$routeProvider', '$locationProvider',
  function($routeProvider, $locationProvider) {
    $routeProvider.
      when('/', {
         templateUrl: 'partials/main.html',
         controller: 'MainCtrl'
      }).when('/show', {
         templateUrl: 'partials/show.html',
         controller: 'ShowCtrl'
});
$locationProvider.html5Mode(false).hashPrefix('!');
}]);

HTML5 mode can provide pretty URLs, but it does require configuration changes on the web server in most cases. The changes are different for each individual web server, and can differ for different server installations as well. HTML5 mode also handles URL changes in a different way, by using the HTML History API for navigation.

Using HTML5 mode is just a configuration change in AngularJS, and we won’t cover the needed server changes in this book as our focus is on AngularJS. The AngularJS site has documentation on the changes needed for all modern web servers when HTML5 mode is enabled. Using this mode has some benefits, but we will stick with hashbang mode in our chapter exercises.

Hashbang mode is used to support conventional search engines that don’t have the ability to execute JavaScript on Ajax sites like those built with AngularJS. When a conventional search engine searches a site built with AngularJS that uses hashbangs, the search engine replaces the #! with ?_escaped_fragment_=. Conventional search engines expect the server to have HTML snapshots at the location where _escaped_fragment_= is configured to point. HTML snapshots are merely copies of the HTML rendered version of the website or application.

Modern Search Engines

Fortunately, modern search engines have the ability to execute JavaScript, as announced by Google in a news release on May 23, 2014. Hashbang mode also allows AngularJS applications to store Ajax requested pages in the browser’s history. That process often simplifies browser bookmarks.

AngularJS Templates

AngularJS partials, also called templates, are code sections that contain HTML code that are bound to the <div ng-view></div></div> tag shown in the index.html file earlier in this chapter. If you look back at the complete app.js file, you can see that different templateUrl values are defined for each route.

The main.html and show.html files listed next show the two defined partials (templates). The templates contain just HTML code, with nothing special at this time. Later, we will use AngularJS’s built-in template language to display dynamic data in our templates:

<!-- chapter1/main.html -->

<div>Hello World</div>
<!-- chapter1/show.html -->

<div>Show The World</div>

As the user clicks on the different links, the value assigned to <div ng-view> is replaced with the content of the associated template files. The value of controller defined for each route references the controller component (of the MVC pattern) that is defined for each particular route.

The next sections provide a brief overview of each AngularJS MVC component and how it is used, to give you a better understanding of how AngularJS works. Unlike most JavaScript client-side frameworks, AngularJS provides the model, view, and controller components for use in all applications. That often helps developers familiar with design patterns to quickly grasp AngularJS concepts.

AngularJS Views (MVC)

Many JavaScript client-side frameworks require you to actually define the view classes in JavaScript, and they can contain anywhere from a few to hundreds of lines of code. Such is not the case with AngularJS. AngularJS pulls in all the templates defined for an application and builds the views in the document object model (DOM) for you. Therefore, the only work you need to do to build the views is to create the templates.

Building views in AngularJS is a simple process that uses mostly HTML and CSS. The simplicity of AngularJS views is a huge time-saver when you’re building AngularJS applications. We will cover creating templates in more detail in Chapter 5.

AngularJS Models (MVC)

Many JavaScript client-side frameworks also require you to create JavaScript model classes. That is also not the case with AngularJS. AngularJS has a $scope object that is used to store the application model. Scopes are attached to the DOM. The way to access the model is by using data properties assigned to the $scope object.

The AngularJS $scope helps to simplify JavaScript applications considerably. Other JavaScript frameworks often encourage placing large amounts of business logic inside the model classes for the particular framework. Unfortunately, that practice often leads to duplicated business logic. In a large project, that can lead to thousands of lines of useless code. We will talk more about models in Chapter 7.

AngularJS Controllers (MVC)

AngularJS controllers are the tape that holds the models and views together. The controller is where you should place all business logic specific to a particular view when it’s not possible to place the logic inside a REST service. Business logic should almost always be placed in backend REST services whenever possible; this helps to simplify AngularJS applications.

When business logic placed inside an application is used by multiple controllers, it should be placed in AngularJS non-REST services instead. Those services can then be injected into any controller that needs access to the logic. We will cover non-REST services in Chapter 8 in great detail.

Controller Business Logic

The following code shows the contents of the controllers.js file. At the start of the file we define the helloWorldController module. We then define two new controllers, MainCtrl and ShowCtrl, and attach them to the helloWorldController module. Business logic specific to the MainCtrl controller is defined inside that controller. Likewise, business logic specific to the ShowCtrl controller is defined inside the ShowCtrl controller. Notice that $scope is injected into both controllers. The $scope that is injected into each controller is specific to that controller and not visible to other controllers:

/* chapter1/controllers.js */

'use strict';
/* Controllers */

var helloWorldControllers = 
angular.module('helloWorldControllers', []);

helloWorldControllers.controller('MainCtrl', ['$scope', 
function MainCtrl($scope) {
  $scope.message = "Hello World";
}]);

helloWorldControllers.controller('ShowCtrl', ['$scope', 
function ShowCtrl($scope) {
  $scope.message = "Show The World";
}]);

As you can see, we are now using the model to populate the messages that get displayed in the templates. The following code shows the modified templates that use the newly created model values. The line $scope.message = "Hello World" in the MainCtrl controller is used to create a property named message that is added to the scope (which holds the model attributes). We then use the double curly braces markup ({{}}) inside the main.html template to gain access to and display the value assigned to $scope.message:

<!-- chapter1/main.html -->

<div>{{message}}</div>

Using double curly braces is AngularJS’s way of displaying scope properties in the view. The double curly braces syntax is actually part of the built-in AngularJS template language.

Likewise, we use the value assigned to the message property with the line $scope.message = "Show The World" in the ShowCtrl controller to populate the message displayed in the show.html template. We use the double curly braces markup inside the show.html template as before to gain access to and display the model property:

<!-- chapter1/show.html -->

<div>{{message}}</div>

Integrating AngularJS with Other Frameworks

AngularJS can be integrated into existing applications that use other frameworks. Those may be other JavaScript client-side frameworks, or web frameworks like Spring MVC or CakePHP. You could take an application written in Java and add some new client-side functionality very easily using AngularJS, cutting development time considerably.

Adding a new AngularJS shopping cart to an existing Java application would be a good example to consider. The existing Java application could be written with the Spring framework and use Spring MVC as the web framework. Adding a shopping cart built with Java using Spring MVC could be a time-consuming process. That, however, would not be the case with AngularJS.

You could quickly build a shopping cart with AngularJS and be up and running in a few hours, easily integrating the cart into the existing Java application. Not only would you be able to build the cart faster, but you could quickly add unit testing to increase coverage and reduce the application’s defects. AngularJS was designed to be testable from the very beginning; that is one of the key features of AngularJS and a major reason for selecting it over other JavaScript client-side frameworks. We will talk about testing AngularJS applications in the next section.

Testing AngularJS Applications

In recent years continuous integration (CI) build tools such as Travis CI, Jenkins, and others have risen in popularity and usage. CI tools have the ability to run test scripts during a build process and give immediate feedback by way of test results. CI tools help to automate the process of testing software and can often alert developers of software defects as soon as they occur.

There are two types of AngularJS tests that integrate well with CI tools. The first type of testing is unit testing. Most developers are familiar with unit testing; they can often identify software defects early in the development process by testing small units of code. The second type of testing is end-to-end (E2E) testing. E2E testing helps to identify software defects by testing how software components connect and interact.

There are many testing tools used for unit testing AngularJS applications. Two of the most popular are Karma and JS Test Driver. Karma, however, is quickly becoming the top choice for AngularJS development teams. The most popular E2E test tool for end-to-end testing of AngularJS applications is a new tool called Protractor. Both tools integrate well with CI build tools.

Large AngularJS development teams will find testing AngularJS applications with continuous integration tools to be a huge time-saver. Often a failed CI test is the first indication of a defect for large teams. Small teams will also see many advantages to CI-based testing. AngularJS developers should always develop both unit tests and end-to-end tests whenever possible.

Throughout this book, we will cover both unit testing and end-to-end testing. We will use both Karma and JsTestDrive for unit testing, and we will use Protractor for E2E testing.

Conclusion

We will cover models, views, and controllers in great detail in later chapters, using those components to build working applications that show the power of AngularJS. We will show how all three components work together to simplify the job of building JavaScript client-side applications. We will also cover building both unit tests and end-to-end tests for AngularJS applications.

Chapter 2 will focus on helping you set up a development environment for HTML5. We will also download the latest versions of AngularJS, jQuery, and Twitter Bootstrap and add those to our sample project.

Get Learning AngularJS now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.