AngularJS is described as a "Superheroic JavaScript MVW Framework" (where MVW stands for Model-View-Whatever). Google search's content description for AngularJS is as follows:
"AngularJS is what HTML would have been, had it been designed for building web-apps. Declarative templates with data-binding, MVW, MVVM, MVC, dependency injection, and great testability story all implemented with pure client-side JavaScript!"
Tip
MVVM is a pattern used in building Windows Presentation Foundation (WPF) applications. A ViewModel represents the model for the view and is bound to various UI elements. This is called data binding. Typically, if the ViewModel changes, the UI elements update themselves, and if a value is changed in any of the UI elements (because of user interaction or otherwise), the underlying ViewModel gets updated. This is called two-way data binding. This is a very powerful concept, as we'll see in the later chapters. The developer does not have to update the UI whenever there is a change in the ViewModel and vice versa. This two-way data binding leads to the elimination of a lot of boilerplate code.
So, what do we gain by having MVVM and MVC in the same framework? As explained earlier, MVVM gives AngularJS the data binding power, and MVC helps you build applications that follow a clean separation of concerns. Testing monolithic applications is very difficult. MVC gives a proper structure to your applications, and different components can be tested individually.
Since AngularJS supports MVC and MVVM architectural patterns, it's described as the MVW (Model-View-Whatever) or MV* framework.
In this chapter, we will:
Compare and contrast frameworks and libraries
Compare and contrast Angular with server-side MVC frameworks
Compare and contrast Angular with other client-side MVC frameworks
Find out why to choose Angular over other alternatives
Learn about data binding (and two-way data binding)
Learn how to bind a collection of data
Find out some naming conventions and learn how to organize Angular applications
You have two choices to aid your development efforts—either choose a framework like Rails or AngularJS or choose smaller libraries. The Clojure community (in general) dislikes frameworks, so there wasn't a full-fledged web framework such as Rails in the Clojure landscape for long. Let's look at the pros and cons of choosing one over the other:
So, why should one choose a client-side JavaScript MVC framework over other server-side frameworks, such as Rails or Asp.Net MVC? Typically, the controller methods of any server-side MVC framework return views (that is, a fully formed HTML). However, there are cases when a view needs some data through Ajax calls (for obvious reasons). In such cases, the question arises as to which controller (method) should send this data. This leads to complexities on two fronts, which are described here:
The view becomes complex: In this case, you have to understand not only the part of the view that is generated by the server, but also all the AJAX interactions happening on the view. Then, you have to decide where to include the JavaScript code related to the view—in the same view in script tags or in a separate JavaScript file. Often, a server-side MVC framework uses a different template engine to build the HTML. This problem can be mitigated using a template engine such as Handlebars (http://handlebarsjs.com/).
The controller becomes complex: Some of the controller methods return complete views, while others return data. If you are using a client-side MV* framework, then the server-side controllers are API controllers, which only send data to the client. It is up to the client to display the data in whichever way it pleases. This makes the controllers simpler.
Similarly, the client-side MV* framework itself gives you some well-defined mechanisms to organize your code as per the MVC paradigm (or whatever convention the framework wants you to follow). So, the view code also becomes simpler and organized. Moreover, every interaction of the view with the server happens through Ajax calls. This too brings uniformity of communication.
While researching for frontend JavaScript frameworks, you'll realize that there are four main open-source contenders: AngularJS, Backbone (http://backbonejs.org/), Ember (http://emberjs.com/), and, the latest kid on the block, React from Facebook (http://facebook.github.io/react/).
Sure, there is jQuery, but it is a library used mainly for DOM manipulations, event handling, and Ajax communication. Similarly, Knockout (http://knockoutjs.com/) is a small framework/library that provides data binding, which greatly simplifies dynamic JavaScript UIs with the MVVM pattern. Likewise, React only caters to the View layer (V in MVC) and isn't a full MVC framework.
However, for a large-scale, database-backed web application, you'll need more than what libraries such as jQuery or Knockout provide. I have no experience with Backbone, Ember, or React, so here are a few links that will help you compare them:
Angular Backbone or Ember: Which is best for your Build? (https://www.codeschool.com/blog/2014/05/15/angular-backbone-or-ember-which-is-best-for-your/)
Angular Backbone Ember: The best JavaScript framework for you (http://readwrite.com/2014/02/06/angular-backbone-ember-best-javascript-framework-for-you)
Backbone and Angular: Demystifying the myths (http://blog.nebithi.com/backbone-and-angular-demystifying-the-myths/)
So, this begs the question, "Why should you choose AngularJS?" The choice of framework depends on a lot of factors—sometimes even personal preferences play a role in deciding a framework. However, let's look at some of the technical and pragmatic reasons that justify choosing AngularJS over other frameworks:
Documentation: Google maintains an excellent and in-depth documentation for AngularJS at https://docs.angularjs.org/api.
Books: There is a wealth of excellent books on AngularJS, such as Mastering Web Application Development with AngularJS (https://www.packtpub.com/web-development/mastering-web-application-development-angularjs), Mastering AngularJS Directives (https://www.packtpub.com/application-development/mastering-angularjs-directives), and many others.
Data binding: With two-way data binding, when you update the DOM, your model gets updated and vice versa. This leads to code reduction.
POJO: Plain old JavaScript objects can be used for data binding. You don't need any special syntax to achieve data binding.
The $http service: This simplifies Ajax communication.
The $resource service: This provides a higher level abstraction than the
$http
service. This service is used to communicate with RESTful APIs.HTTP interceptors: For purposes of global error handling, authentication, or any kind of synchronous or asynchronous preprocessing of request or postprocessing of responses, we can use HTTP interceptors.
Directives: This is a complex but very powerful feature of AngularJS. This feature (https://www.packtpub.com/application-development/mastering-angularjs-directives) is the one that "teaches old HTML, some new tricks". Using directives, you can build custom HTML elements, attributes, and so on.
Dependency injection: Most of the server-side object-oriented languages have dependency-injection support available through some library/framework. You can expect the same ease of use with AngularJS's built-in support for dependency injection in your favorite language—JavaScript.
Unit testing support: This is a must when developing with a dynamic language such as JavaScript. AngularJS has excellent support for unit testing—it comes with mocks for a number of its built-in services.
Support: AngularJS is backed by none other than Google. It becomes easy to convince your boss if a company like Google is behind a framework or technology.
Community: This plays an important role when you are learning something new. There are already a lot of questions answered on sites such as StackOverflow (http://stackoverflow.com/). You'll find many more resources on Twitter and many other websites.
Companion frameworks: Ionic (http://ionicframework.com/) is a frontend framework to develop hybrid mobile apps with HTML5. This framework is optimized for AngularJS.
Data binding is the process that establishes a connection between the application UI and data. So, data binding has two participants: the model (or the getter and setter properties of the model) and the UI element (to which the model is bound). In the case of AngularJS, the UI elements are the various DOM elements that make up our UI.
When the data changes its value, the UI elements that are bound to the data reflect changes automatically. Conversely, when the data shown in the UI element changes, the underlying model is updated to reflect the changes.
Every programming language has a venerable Hello World code example that forms the starting point in the study of that language. So, how can AngularJS be left behind?
The following is AngularJS's Hello World example. This example shows data binding in action:
<!DOCTYPE html> <html> <head> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.17/angular.min.js"></script> <title>Hello world from AngularJS</title> </head> <body> <div ng-app> <div> <label>Name:</label> <input type="text" ng-model="yourName" placeholder="Enter a name here"> <hr> <h1>Hello {{yourName}}!</h1> </div> </div> </body> </html>
(hello-world.html
)
Let's take a look at the preceding code (especially the highlighted parts of the code):
Inside the script tag, we included a reference to
angular.min.js
.The
ngApp
directive is used to autobootstrap an AngularJS application. This directive is a part of theng
core module. Theng
module is loaded by default when an AngularJS application is started. ThengApp
directive designates the root element of the application. Whenever Angular finds the ngApp directive, it loads the module associated with the directive. From this point on, Angular can start its magic. This directive is typically placed near the root element of the page, for example, on the<body>
or<html>
tags. Alternatively, it can be placed on the part of the HTML that we want AngularJS to control.Directives: These are markers on a DOM element (such as an attribute, element name, comment, or CSS class). They tell AngularJS's HTML compiler to attach a specified behavior to that DOM element or even transform the DOM element and its children. You can read more about directives in the AngularJS directive guide at https://docs.angularjs.org/guide/directive. Also, notice that the names of the AngularJS directives we've used so far are
ngApp
andngModel
, whereas in the HTML document, we are usingng-app
andng-model
. By convention, directives are named using camelCase in JavaScript and snake case within your HTML. Snake case means all lowercase, using either:
,-
, or_
to separate the words. So,ng-app
can also be written asng_app
orng:app
.Bootstrapping: This is the Angular initialization process and can be done in one of two ways: automatic initialization (which is the recommended way) or manual initialization (in cases when you need to perform an operation before Angular compiles a page). The automatic initialization process, as explained above, starts when Angular encounters an ngApp directive. You can read more about the AngularJS bootstrap process in the AngularJS bootstrap guide available at https://docs.angularjs.org/guide/bootstrap.
The
ngModel
directive bindsinput
,select
, andtextarea
(or custom form control) to a property on the scope.Scope refers to the application model and acts as the glue between application controller and the view. You can read more about scopes in the AngularJS scope guide at https://docs.angularjs.org/guide/scope.
{{yourName}}
renders the value of this variable in the DOM element. It means whatever value was stored in theyourName
variable is extracted and displayed in the enclosing DOM element.So, in short, we created a
yourName
variable on the scope and bound it to the input element (which means, the data entered in the input box is stored in this variable). Then, we just showed the value of theyourName
variable in theh1
element. So, as soon as you start typing into the input textbox, you'll see the same text reflected in theh1
element. This is one-way data binding in action. Isn't it cool!
You'll also notice that there are no IDs assigned to any of the HTML elements! This is possible because of the power of data binding—you'll hardly need to retrieve a DOM element based on its ID because data-bound properties on the scope will do the magic.
Let's extend the preceding example to illustrate two-way data binding:
<!DOCTYPE html> <html> <head> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.17/angular.min.js"></script> <title>AngularJS - Two way data binding</title> </head> <body> <div ng-app> <div> <h2 style="color:blue;">One way data binding? Cool!</h2> <label>Name:</label> <input type="text" ng-model="yourName" placeholder="Enter a name here"> <h3>Hello {{yourName}}!</h3> </div> <hr /> <div> <h2 style="color:green;">Two way data binding? Great!</h2> <textarea type="text" ng-model="newName" placeholder="Enter some text to change the value of the underlying model"></textarea> <button ng-click="yourName = newName"> Change the underlying model's value </button> </div> </div> </body> </html>
(two-way-data-binding.html
)
We've made very few changes to our preceding Hello World example. We introduced a
<textarea>
element and bound it to a new model variable callednewName
.We added a
<button>
element, and we are handling its clicked event (using thengClick
directive). Inside the click event, we just assigned the value of thenewName
new model to our old variableyourName
.As soon as you enter some text in the
textarea
value and click on the Change the underlying model's value button, thetextarea
value is reflected in the Name textbox and the Hello label.This shows two-way data binding in action. The UI control reflects the value of the underlying model and vice versa.
Let's see how to bind data when we have a collection (or a list) of values. For clarity, we'll only show the important part of the code.
<body ng-app="collectionBindingApp"> <div ng-controller="EmployeeCtrl"> <h1>Employee data:</h1> In a list - <ul> <li ng-repeat="employee in employeeData.employees"> Employee number {{$index}} is - {{employee.name}} </li> </ul> <br />In a table - <table> <tr> <th>Name</th> <th>Age</th> </tr> <tr ng-repeat="employee in employeeData.employees"> <td>{{employee.name}}</td> <td>{{employee.age}}</td> </tr> </table> </div> <script src="app.js"></script> </body>
(collection-binding-ex\index.html
)
You're now familiar with the ng-app
directive. AngularJS starts its magic from this point onwards. We then attach EmployeeCtrl
to the div
element using the ng-controller
directive. The ng-repeat
directive instantiates a template once per item in the collection, which is employeeData.employees
here. So, in the first instance in the preceding code, it repeats the <li>
elements, whereas in the second case, it repeats the <tr>
elements. Each template instance gets its own scope, and $index
is set to the item index or key.
Let's look at the controller now (again, for clarity, we are showing a part of the code):
var app = angular.module('collectionBindingApp', []); app.controller('EmployeeCtrl', ['$scope', function ($scope) { var Employee = function (name, age) { this.name = name; this.age = age; }; var getEmployees = function () { return [ new Employee("First employee", 56), new Employee("Second employee", 44), new Employee("Last employee", 32) ]; }; $scope.employeeData = { employees: getEmployees() }; } ]);
(collection-binding-ex\app.js
)
Tip
Downloading the example code
You can download the example code files from your account at http://www.packtpub.com for all the Packt Publishing books you have purchased. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.
We first create a new module called collectionBindingApp
using the below API :
angular.module(name, [requires], [configFn]);
Here name
is the name of the module to create or retrieve. The second argument is optional—if it is specified then a new module is being created, else an existing module is being retrieved for further configuration. The third parameter is an optional configuration function for the module.
We store the module in the app
variable. This app
variable is available globally and is used to associate controllers, directives, filters, and so on with this module. Then we create a controller called EmployeeCtrl
on this new module.
We should use a controller to set up the initial state of the $scope
object and to add behavior to the $scope
object. We declared our new controller, called EmployeeCtrl
, and associate it with the collectionBindingApp
module. This controller has a few functions to generate test data, but in real-life scenarios, you'll typically fetch data from RESTful services (for which you can use the $http
service or the $resource
service). So, we set the state here by assigning some employees to the $scope.employeeData
object. An advantage of using an object is that you don't clutter $scope
with too many variables. So, when you run the example, you see the employee data, first in a list (which also shows the index) and then in a tabular form.
It would've become pretty obvious by now that data binding can reduce a lot of DOM manipulation code from the application and is a powerful technique. AngularJS brings data-binding capabilities within the realm of web applications. We can use it in our favorite platform, that is, the Web, HTML5, and JavaScript.
The ngRoute
(https://docs.angularjs.org/api/ngRoute) module and the ngView
(https://docs.angularjs.org/api/ngRoute/directive/ngView) directive are the secret sauces that let us write Single Page Applications (SPAs) with ease. We configure which views are to be shown for which URLs using the $routeProvider
service. This service comes with the ngRoute
module. This module comes with the angular-route.js
library, so we have to include it separately. So, let's see them in action:
<!DOCTYPE html> <html> <head> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular-route.min.js"></script> <title>Routing example</title> </head> <body ng-app="routeApp"> Choose:<br><br> <a href="#employees">Employees</a><br> <a href="#departments">Departments</a> <div ng-view></div> <script src="app.js"></script> <script src="employee.ctl.js"></script> <script src="department.ctl.js"></script> </body> </html>
(route-ex/index.html
)
First, we included the angular-route.min.js
library. Then, as usual, we set up a routeApp
module and then we set up two links—one each to navigate to employees and departments. Note that the links have a leading #
because we don't want the browser to actually navigate to the employees.html
or departments.html
page. Finally, we added the ng-view
directive to our div
element, which works together with the $route
service. It serves as the placeholder where the HTML contents of various templates are rendered as per the current route. Hence, it includes the rendered template of the current route into the main layout (index.html
). The configuration of routes is done in the following app.js
file:
var app = angular.module('routeApp', [ 'ngRoute' ]); app.config(function ($routeProvider) { $routeProvider .when('/employees', { templateUrl: 'employee.tpl.html', controller: 'EmployeeCtrl' }) .when('/departments', { templateUrl: 'department.tpl.html', controller: 'DepartmentCtrl' }) .otherwise({ redirectTo: '/' }); });
(route-ex/app.js
)
We loaded the ngRoute
module as a dependent of the routeApp
module. Next, we configured various routes of the module using $routeProvider
. Here, we are saying that whenever the URL matches /employees
, the employee.tpl.html
template should be inserted in the ng-view
placeholder of the index.html
file with EmployeeCtrl
as the controller. This also applies to the /department
URL.
The EmployeeCtrl
controller in route-ex/employee.ctl.js
is similar to the one in the previous example, and DepartmentCtrl
in route-ex/department.ctl.js
mimics it. The templates for employee view and department view are also similar, as shown here:
<br> <div> <h1>Employee data:</h1> <ul> <li ng-repeat="employee in employeeData.employees"> Employee - {{employee.name}} is - {{employee.age}} years old </li> </ul> </div>
(route-ex/employee.tpl.html
)
Just as the employee template in the preceding code shows employee data, the department template shows department data. When you run the application and click on the employee link, you see the employee data, and ditto for the department link, without any page refreshes. Although this is a simple example, you can see how easy Angular makes it to write SPAs.
Other AngularJS directives such as ngShow
, ngHide
, ngChecked
, and ngSelected
are among the various other directives that help us in building great-looking UIs with minimal DOM manipulation code. AngularJS API docs (https://docs.angularjs.org/api) is a great place for exploring various directives, services etc. that Angular provides.
The success of a project can be judged not only by the timely delivery of working code but also by other factors such as:
How much of the code is covered by tests
How well organized the codebase is (in a proper folder structure)
How consistent the naming convention is
How easy it is for someone who is new to the project to understand the code
The naming conventions and many other factors are a matter of personal taste. However, for the sake of consistency, it's always advisable to agree on certain naming conventions and best practices to be followed for any important projects.
As discussed in Appendix A, Yeoman, tools such as Yeoman (http://yeoman.io/) help with the scaffolding and setting up of the initial folder structure. Similarly, code beautifiers available in various IDEs help in arranging the code in a single file to follow accepted norms with spaces, tabs, new lines, and so on.
You've got a taste of some of the naming conventions that I've followed in the preceding examples. For example, the template file has been named with a .tpl.html
extension. Similarly, a controller file is named with a .ctl.js
extension. Although it's a trivial change, it adds a lot to the overall code readability. Similarly, the names of the controllers starts with a capital letter (EmployeeCtrl
), whereas the names of all other components start with a small letter (collectionBindingApp
).
Yeoman organizes the code by type, that is, it has folders for controllers, views, services, and so on. This is OK at the beginning but has a distinct disadvantage: the files that logically belong together to a feature, that is, a view, a controller, and various services the controller needs, are in different folders. So, it becomes difficult to locate these files. When you are working on a particular feature, you are going to need these files at the same time.
So, the other option is to organize the code by feature or by component. So, assuming that your project deals with employees, departments, and so on, there will be folders named employees or departments. Views, controllers, services, and directives belonging to a component live in the particular component's folder.
You may refer to the following links for more details on organizing the Angular code:
AngularJS style guide at https://github.com/mgechev/angularjs-style-guide
AngularJS best practices at https://github.com/GrumpyWizards/Angular
Best practices recommendations for Angular App structure at https://docs.google.com/document/d/1XXMvReO8-Awi1EZXAXS4PzDzdNvV6pGcuaF4Q9821Es/pub
The Google JavaScript style guide at http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml; this is a good place for general JavaScript conventions
Check out AngularJS Batarang (https://chrome.google.com/webstore/detail/angularjs-batarang/ighdmehidhipcmcojjgiloacoafjmpfk?hl=en), a Chrome extension. This helps in debugging JavaScript applications written using AngularJS. It gets added as an extra AngularJS tab in the developer tools where it shows different scopes and models. We can check which models are attached to which scope.
Also, check out Built with AngularJS (https://builtwith.angularjs.org/) for interesting examples of sites/applications built using AngularJS.
In this chapter, we compared and contrasted frameworks versus libraries, Angular versus the server-side MVC frameworks, and Angular versus the other client-side JS MVC frameworks. We also looked at some of the important reasons as to why we should choose Angular. Then, we talked about data binding and why and how it's powerful and consequently leads to reduction of code. Finally, we looked at a few of the naming conventions and how to organize Angular applications.
In the next chapter, we'll learn about advanced Angular concepts such as IoC and filters. You'll also learn how to fetch data using the $http
and $resource
services.