Notes on AngularJS

advertisement
Notes on AngularJS
Created 07/06/13
Updated 09/20/13, Updated 10/08/13, Updated 12/08/13, Updated 01/14/14, Updated 05/15/14, Updated 07/20/14
Updated 09/15/14, Updated 10/09/14, Updated 11/05/14, Updated 01/23/15, Updated 02/19/15, Updated 03/15/15
Updated 04/29/15, Updated 05/14/15, Updated 05/26/15
Introduction
AngularJS is an open-source JavaScript framework, maintained by Google, which assists with running single-page
applications. Its goal is to augment browser-based applications with model–view–controller (MVC) capability, in
an effort to make both development and testing easier.
The library reads in HTML that contains custom tag attributes; those custom attributes use AngularJS “directives”,
and binds input or output parts of the page to a model represented by standard JavaScript variables. The values of
those JavaScript variables can be manually set, or retrieved from static or dynamic JSON resources.
There is a core library and set of approximately 20 additional modules (such as for resources, animation, routing,
cookie processing, and other functions typical of a modern JavaScript application library) which can be selected
from. Angular doesn’t provide the visual representation of on-screen elements (such as improvements to buttons,
adding layouts, adding sliders, adding charts, etc.), but it supports the development of such, particularly through its
facility to support application-designed extensions to its building blocks, which are called “directives”
The current stable version is 1.3.15, released in mid-March 2015. There is a 1.4.x version in release candidate
status.
A prior current stable version was 1.2.28, released in early 2015.
There are also plans for Angular 2 to be released at the end of the year, but that is out of scope for this document.
Angular 2 is intended to use the JavaScript object/class model that is becoming standard in Java during this period,
so that the API to Angular will be more like OO-toolkits.
Resources
https://www.airpair.com/angularjs/posts/top-10-mistakes-angularjs-developers-make
See http://www.angularcourse.com/ This is a free online class presented by gordonmzhu@gmail.com. When
you're done, you'll have full web app built with AngularJS, Firebase, Twilio, and Zapier.
“Unraveling AngularJS 1.3 (With Over 130 Complete Samples)” by Istvan Novak. Amazon Digital Services, Inc.,
March 2015, 583 pages. Available for Kindle for $4.79. Rated 5.0 stars on Amazon.com. Just published, this is a
guide to learning Angular by writing an application that manages a list of dives. Builds up the code piece by piece,
with all 130 stages in developing provided as runnable source. We feel that this is second-best overall learning tool
at present, as the writing is slightly less clear than the Seshadri/Green book. However, the examples are better.
“AngularJS: Up and Running” by Shyam Seshadri and Brad Green. O'Reilly Media, September 2014, 302 pages.
List price $39.99, Amazon price $28.55. Rated 4.6 stars on Amazon.com. We feel this is the best overall book at
present. This is an updated version of the authors’ prior book. About 50% longer, and updated to current versions.
We got this in October 2014.
“Node.js, MongoDB, and AngularJS Web Development” by Brad Dayley. Addison-Wesley Professional, June
2014, 696 pages. List price $49.99, Amazon price $32.12, used from $28.12. Rated 3.5 stars in Amazon.com.
Available on IEEE Safari books. Quite comprehensive – probably the most complete book of its kind. Reviews
were very good, but there were some concerns about how the book was laid out.
Page 1
“ng-book” an online book that you subscribe to by Art Lerner. First released in 2013, latest update covers release
1.2.10. The price is $39 for an individual subscriber at www.ng-book.com. There is also a $79 package that
includes more example code and a 3 hour video.
“Pro AngularJS” by Adam Freeman. APress, April 2014, 683 pages. List price $44.99, Amazon Kindle price
$36.27, used from $32.27. Rated 4.4 stars on Amazon.com.
“AngularJS Directives” by Alex Vanston. Packt Press, September 2013, 110 pages. List price $29.69, Amazon
price $29.69. Rated 5 stars on Amazon.com. One reviewer wrote: It is well written and explains almost any aspect
of directives I can imagine. If you struggle with the AngularJS docs (which is almost certainly the case) you should
definitely look at the book. Alex Vanston wrote it for people who managed their first steps with AngularJS but need
more. Although there is a little introduction you should be able to read JavaScript, maybe even know what jQuery is
and absolutely should have made some experiments with AngularJS. It is not a book for beginners.
“Mastering Web Application Development with AngularJS” by Pawel Kozlowski, Peter Bacon Darwin. Packt Press,
August 2013, 373 pages. Rated 4.3 stars on Amazon.com. This book covers all aspects as a reference, including
directory structure, and suggestions for using various features. Improves on the documentation and typical
examples. One reviewer wrote “You don’t need to buy anything else!”.
“Recipes with Angular.js” by Frederik Dietz. Kindle book, June 30, 2013. This is a self-published book available
from Amazon for $9.99 and is rated 4 stars. Contains many useful examples. He also publishes a free online
version at http://fdietz.github.io/recipes-with-angular-js/
“AngularJS” by Brad Green and Shyam Seshadri. O’Reilly Press, April 2013, 196 pages. List price $16.04,
Amazon price $13.99, used from $13.99. Rated 3.5 stars on Amazon.com. One of the first books to appear on this
package. We have used this for basic learning of the concepts, but have changed to the second edition, mentioned
above.
The Philosophy of AngularJS
AngularJS is built around the belief that declarative programming should be used for building UIs and wiring
software components, while imperative programming is excellent for expressing business logic. The framework
adapts and extends traditional HTML to better serve dynamic content through two-way data-binding that allows for
the automatic synchronization of models and views. As a result, AngularJS deemphasizes DOM manipulation and
improves testability.
Design goals




Decouple DOM manipulation from application logic. This improves the testability of the code.
Regard application testing as equal in importance to application writing. Testing difficulty is dramatically
affected by the way the code is structured.
Decouple the client side of an application from the server side. This allows development work to progress
in parallel, and allows for reuse of both sides.
Guide developers through the entire journey of building an application: from designing the UI, through
writing the business logic, to testing.
Angular follows the MVC pattern of software engineering and encourages loose coupling between presentation,
data, and logic components. Using dependency injection, Angular brings traditional server-side services, such as
view-dependent controllers, to client-side web applications. Consequently, much of the burden on the backend is
reduced, leading to much lighter web applications.
Files in the Distribution
Page 2
Analyzing an AngularJS app
The Application
We will be reviewing a recipe management application.
Relationship between Model, Controller, and Template
Based on MVC, where the model is represented by JavaScript arrays which are placed within $scope. The
controllers are objects which export methods, and typically the controllers operate on information which is located
in the model and the HTTP request object.
The views are represented by the HTML which has been augmented with Angular directives and expressions to
form templates. When a template is rendered, the directives and expressions are evaluated. The directives might
call for a portion to the DOM to be generated or revised in the browser.
The Model
Holds data. Unlike Backbone or ExtJS, the model support in Angular is quite simple: you basically attach
everything by name to $scope. This does allow you to avoid the pollution of the JavaScript global name space.
However there is no support for writing classes to be instantiated as model content, as in Backbone or ExtJS, as
Angular 1.x does not have a class/instance/extension facility.
To deal with collections of content, you simply use more JavaScript arrays. There is no concept within regular
Angular of a Collection as in Backbone or a Store as in ExtJS, which are objects that have an associated class
definition, manage the instances of the model data, provide events when changes occur, or support fetching and
updating of content from the backend. The only exception to this is the Resources plugin, which is described below.
Page 3
Controllers, Directives, and Services
This is where your business logic is to be located. Controllers are implementations of code which can be called, and
are organized into JavaScript files that are typically paired with the HTML files (the templates) that implement the
display structure. The combination of a controller file and the templates is typically called a “module”.
This combination is controlled through the directives added to the DOM, such as ng-controller, which indicates the
controller implementation file name for a given region of the DOM.
There is also a controller-like object for the whole application. Typically this contains dispatch routings (if so, your
app must include the ngRoute module, which is no longer included by default in AngularJS after version 1.1.6).
Here is an example of using ngRoute:
angular.module('myApp', [
'ngRoute'
]).
config(['$routeProvider', function ($routeProvider) {
$routeProvider.when('/', {
templateUrl: 'partials/landing_page.html',
controller: 'LandingPageController'
});
$routeProvider.when('/waitlist', {
templateUrl: 'partials/waitlist.html',
controller: 'WaitlistController'
});
$routeProvider.otherwise({redirectTo: '/'});
}]);
Directives have two levels of meaning: those directives that are provided within AngularJS, such as “ng-repeat” or
“ng-show”, and those defined by your application (or libraries), and define new elements and their behavior.
Services are support or utility functions that are used by more than one controller, and are injected into the
controller.
Templates
As mentioned above, these consist of HTML plus directives.
Templates can contain Angular expressions in {{ }}.
The outermost, main template, is the index.html template. This is the base of our single-page application, and all
the other views are loaded within the context of this template.
Since the templates (particularly the index.html template) are the first portions of your application which are
loaded into the browser, they must specify the loading of the Angular library JavaScript files, the added plugins
JavaScript files, the application-level controller JavaScript file, and then the controllers for the different modules
(which are more JavaScript files). Hence, the ordering and organization of these steps in index.html is quite
critical.
Your scripts may be included at the top (header) section, or the bottom of the body (which is preferred for faster
loading).
The templates which are loaded for the individual modules can be organized in a number of ways. This document
tries to help you organize them based on best practices and to match the function of the routing directives.
Tests
The first and most important kind of test is the unit test. This tests that the controllers (and directives, and services)
that you have developed are correctly structured and written, and that they do what you would expect them to.
Page 4
Controllers
Controllers are where your JavaScript will be located. They can be in their own file, or multiple controllers defined
in one file. What is common to all controllers is that they define a set of methods which can be called from the
events on the screen (template). For instance, a button can have an “ng-click” directive, which indicates the
controller method to be called. In this sense, Angular is more a “declarative” framework, as in jQuery there would
be code written to attach the event handler.
Scope in Controllers
Most controller methods are called with $scope. This is the set of variable definitions available to the controller.
The scope typically contains model instances. Each scope is specific to that controller instance (i.e., the instance
specified for the current subtree of DOM content). The scope only lasts during the time that the controller is active
(i.e., regions of the screen that specify that controller have been rendered).
If there are controllers at several levels of nesting in the DOM, there will be a tree of controllers, and hence a tree of
scopes. Information from parent scopes can be accessed from child scopes.
There is also $rootScope, which is the parent of all $scope objects, and lasts for the entire duration of the
application.
Asynchronous code in Controllers
One of the challenges in writing control code is dealing with the sequences of request/reply callbacks which are
performed against the backend, and chaining the methods which are called in response to each callback. For a
multi-step sequence, this can produce very unreadable code.
The approach taken in modern JavaScript libraries is to define “promises” or “futures”, which provide a simple
syntax for such operations, with a declarative syntax. Angular has an implementation of promises, which support
then() methods. The latter are methods to be run after a response to another method.
The book contains a good explanation of this, and we are only summarizing it here. However, this concept is
important to understand before we get into the discussion about communication with servers, since that uses these
facilities as well.
How Angular uses Directives added to the HTML
Directives are written into the HTML elements, as new HTML attributes. They typically have special names, such
as “ng-”
Most directives take values such as the “ng-repeat” directive. If you write “party in parties” you will get an iteration
over the elements in “parties” without further modification.
Many directives have optional fields in their arguments. For instance, if you write “party in parties |
orderByPriority” you will get objects which contain fields in party and the object id, and sequenced by those object
ids.
Directives and HTML validation
So far, we’ve used Angular’s built-in directives with the ng-directivename syntax. Examples include ngrepeat, ng-view, and ng-controller. Here, the ‘ng’ portion is the namespace for Angular, and the part after
the dash is the name for the directive.
While we prefer this syntax for ease of typing, it isn’t valid in many HTML validation schemes. To support these,
Angular lets you invoke any directive in several ways. The following syntaxes are all equivalent to allow for your
preferred validator to work properly:
Page 5
Because you can use any of these, the Angular documentation lists directives with a camel-case format, instead of
any of these options. For example, ng-repeat is found under the title ngRepeat. As you’ll see in a bit, you’ll use
this naming format when defining your own directives.
Templates and Data Binding
Another important thing to note is that we used the double-curly notation to print the note’s label, but used a
directive called ng-bind for the note’s done field.
There is no functional difference between the two; both take the value from the controller and display it in the UI.
Both of them also keep it data-bound and up to date, so if the value underneath changes, the UI will change
automatically. We can use them interchangeably, because the expression between the double curly braces will
directly drop into the ng-bind.
AngularJS creates scopes or context for various elements in the DOM to ensure that there is no global state and each
element accesses only what is relevant to it. These scopes have a parent-child relation by default, which allows
children scopes to access functions and controllers from a parent scope.
Working with ng-model
The ng-bind directive, or its equivalent double-curly {{ }} notation, which allowed us to take the data from our
controllers and display it in the UI. That gives us our one-way data-binding, which is powerful in its own regard.
But most applications we develop also have user interaction, and parts where the user has to feed in data. From
registration forms to profile information, forms are a staple of web applications, and AngularJS provides the ngmodel directive for us to deal with inputs and two-way data-binding:
<html ng-app="notesApp">
<head><title>Notes App</title></head>
<body ng-controller="MainCtrl as ctrl">
<input type="text" ng-model="ctrl.username"/>
You typed {{ctrl.username}}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.19/angular.js">
</script>
<script type="text/javascript">
angular.module('notesApp', []).controller('MainCtrl', [function() {
this.username = 'nothing';
}]);
</script>
</body>
</html>
In this case, two-way binding is created, in which the input is added to the model.
Page 6
Working with Forms
When we work with forms in AngularJS, we heavily leverage the ng-model directive to get our data into and out of
the form. In addition to the data-binding, it is also recommended to structure your model and bindings in such a way
to reduce your own effort, as well as the lines of code you write.
We can also define validation rules on the fields, such as minimum value length. See table of validators below:
When you use forms (and give them names), AngularJS creates a FormController that holds the current state of
the form as well as some helper methods. You can access the FormController for a form using the form’s name,
as we did in the preceding example using myForm. Things that are exposed as the state and kept up to date with
data-binding are shown below.
Formatting Data with Filters
AngularJS lets us format data or manipulate array collections through filters. In this example we'll take a look at
the formatting filters.
To specify a filter in the HTML template, we can use the common data biding notation {{expression}} and add a
pipe (|) after the expression to format its result, so we'll have something like this {{expression | filter}}. If the filter
accepts some parameters, we can specify them in sequence with the colon (:) character
{{expression | filter:param1:param2}}.
Page 7
A simple filter example would be to use the built-in uppercase formatting filter that formats the content
of stringData turning it to uppercase.
More complex filter example would chain multiple filters together. Each time a pipe character is encountered, the
preceding result will be processed by the filter specified after the pipe. So, in the example, stringData is first turned
to lowercase and then the limitTo filter trims the lowercase string. The limitTo filter accepts a parameter that in this
case says that we want to keep the first 7 characters of the string.
A final example would be to apply a filter in JavaScript. We see that we can apply the date filter in three different
ways, the first one with the usual syntax for the HTML template and the other two directly in JavaScript. Let's take a
look at the two JavaScript filter functions.formatDate1 retrieves the date filter using the $filter variable. That
variable is available for us using Dependency Injection and allows use to retrieve any available filter.
In the example we're saying: give me the date filter function and apply the date and format parameters to the
function.formatDate2 is a different way to achieve the same result. We can retrieve the date filter through
Dependency Injection also specifying as a module function argument (the controller function in this case) the name
of the filter with a Filter suffix.
Organizing Modules with Dependencies
There are typically a number of dependencies for a given module. For instance, most use $scope, and this appears in
the controller declaration for a module.
As we have mentioned above, services can be defined, which provide business logic to a number of controllers and
their modules.
The services are also spelled out in the declaration.
The syntax is similar to that used in RequireJS.
Best Practices
We will keep this section short and concise and expand on it in the following sections.
Use this as a quick guide and refresher when you have any doubts or decision making to do:
 Have one controller, service, directive, or filter per file. Don’t club them into large single files.
 Don’t have one giant module. Break up your applications into smaller modules. Let your main
application be composed of multiple smaller, reusable modules.
 Prefer to create modules and directories by functionality (authorization, adminservices, search, etc.),
over type (controllers, services, directives). This makes your code more reusable.
 Use the recommended syntax of using the module functions
(angular.module('someModule').controller…, etc.) over any other syntax you might see online or
anywhere else.
 Use namespaces. Namespace your modules, controllers, services, directives, and filters. Have
mycompany-chart for directives, myProjectAuthService, and so on. That way, anyone coming in can
quickly distinguish your own code from thirdparty and core AngularJS code.
 Most of all, be consistent. This is not AngularJS-specific, but don’t change the way you name file
Organizing Views
The routing functionality added by this step is provided by angular in the ngRoute module, which is distributed
separately from the core Angular framework (this is provided separately so that you can replace it with the uirouting module, a more advaced version, discussed below).
Page 8
Multiple Views, Routing and Layout Template
Our app is slowly growing and becoming more complex. Before step 7, the app provided our users with a single
view (the list of all phones), and all of the template code was located in the index.html file. The next step in
building the app is to add a view that will show detailed information about each of the devices in our list.
To add the detailed view, we could expand the index.html file to contain template code for both views, but that
would get messy very quickly. Instead, we are going to turn the index.html template into what we call a "layout
template". This is a template that is common for all views in our application. Other "partial templates" are then
included into this layout template depending on the current "route" — the view that is currently displayed to the
user.
Application routes in Angular are declared via the $routeProvider, which is the provider of the $route service.
This service makes it easy to wire together controllers, view templates, and the current URL location in the browser.
Using this feature, we can implement deep linking, which lets us utilize the browser's history (back and forward
navigation) and bookmarks.
Communicating with Servers
Communicating using $http
Interacting with RESTful services
The $q and Promise
Response Interception
Security Considerations
More about Form Elements and Validating Input
There are also form element directives for handling checkboxes, radio buttons, text areas, and more.
The Combo Box
The final HTML form element (which can be used outside forms as well) is the select box, or the drop-down/combo
box as it is commonly known. Let’s take a look at the simplest way you can use select boxes in AngularJS:
<div ng-init="location = 'India'">
<select ng-model="location">
<option value="USA">USA</option>
<option value="India">India</option>
<option value="Other">None of the above</option>
</select>
</div>
In this example, we have a simple select box that is data-bound to the variable location. We also initialize the value
of location to India, so when the HTML loads, India is the selected option. When the user selects any of the other
options, the value of the value attribute gets assigned to the ng-model. The standard validators and states also
apply to this field, so those can be applied (required, etc.).
Display of validation error messages
There are pre-built classes which will be applied to the form elements so that error indication is supported.
Introduction to Directives
The most powerful part of Angular is the ability to create new HTML elements and their behavior.
Page 9
Directives are the AngularJS way of dealing with DOM manipulation and rendering reusable UI widgets. They can
be used for simple things like reusing HTML snippets, to more complex things like modifying the behavior of
existing elements (think ng-show, ng-class, or making elements draggable) or integrating with third-party
components like charts and other fancy doodads.
Here we start with developing a very basic directive, and explore some of the more common options like template,
templateUrl, link, and scopes.
Alternatives to Custom Directives
Before we jump into directives, let’s quickly walk through some other options that might serve us well in the case
that we want reusable HTML, or business logic in our HTML. We have two directives, ng-include and ng-switch,
which can help us in extracting HTML into smaller chunks and deciding when to show and hide them in our HTML.
In many cases, we can use these two directives instead of writing our custom directives.
The ng-include directive takes an AngularJS expression (similar to ng-show and ng-click) and treats its value as the
path to an HTML file. It then fetches that HTML file from the server and includes its content as the child (and the
only child, replacing all other existing content) of the element that ng-include is placed on.
[ng-include example goes here]
The Directives API
Creating a directive is just like creating controllers, services, and filters in that the AngularJS module function
allows us to create a directive by name. The first argument to the function is the name of the directive, and the
second argument is the standard Dependency Injection array syntax, with the last element in the array being our
directive function.
Suppose we want to turn the stock.html file from the previous example into a reusable directive. Let’s start with
how we want to use it in our HTML:
<div stock-widget></div>
If we want to be able to declare that the current div is a stock widget (used as stated previously), we need to declare
or create our directive as follows:
angular.module('stockMarketApp', [])
.directive('stockWidget', [function() {
return {
// Directive definition will go here
};
}]);
We define the stockWidget directive and provide it with a function. This function sets up our directive using
what we call a directive definition object and returns this definition. AngularJS looks at this definition each time it
encounters our directive in the HTML.
A basic pseudo-code template for creating any directive follows:
var myModule = angular.module(...);
myModule.directive('namespaceDirectiveName', function factory(injectables) {
var directiveDefinitionObject = {
restrict: string,
priority: number,
template: string,
templateUrl: string,
replace: bool,
Page 10
transclude: bool,
scope: bool or object,
controller: function controllerConstructor($scope,
$element,
$attrs,
$transclude),
require: string,
link: function postLink(scope, iElement, iAttrs) { ... },
compile: function compile(tElement, tAttrs, transclude) {
return {
pre: function preLink(scope, iElement, iAttrs, controller) { ... },
post: function postLink(scope, iElement, iAttrs, controller) { ... }
}
}
};
return directiveDefinitionObject;
});
Some of the options are mutually exclusive, most of them are optional, and all of them have details that are worth
explaining.
Naming Your Directive: you create a name for your directive with a module’s directive function, as in the
following:
myModule.directive('directiveName', function factory(injectables)
Though you can name your directives anything you like, the convention is to pick a prefix namespace that identifies
your directives and prevents them from colliding with external directives that you might include in your project.
Summary of custom directive benefits
As we’ve seen, directives let us extend HTML’s syntax and turn many application tasks into a do-what-I-mean
declaration. Directives make reuse a breeze: from configuring your app, like with ng-model and ngcontroller, to doing template tasks like ng-repeat and ng-view, to sky’s-the-limit reusable components such
as data-grids, bubblecharts, tool-tips, and tabs.
Example of a Complex Directive
Statement of Problem
You wish to change the CSS of an HTML element on a mouse click and encapsulate this behavior in a reusable
component.
Implement a directive my-widget that contains an example paragraph of text we want to style.
<body ng-app="MyApp">
<my-widget>
<p>Hello World</p>
</my-widget>
</body>
We use a link function in our directive implementation to change the CSS of the paragraph.
var app = angular.module("MyApp", []);
app.directive("myWidget", function() {
var linkFunction = function(scope, element, attributes) {
var paragraph = element.children()[0];
$(paragraph).on("click", function() {
Page 11
$(this).css({ "background-color": "red" });
});
};
return {
restrict: "E",
link: linkFunction
};
});
When clicking on the paragraph the background color changes to red.
Discussion
In the HTML document we use the new directive as an HTML element ‘my-widget’, which can be found in the
Javascript code as ‘my-widget’ again. The directive function returns a restriction and a link function. The
restriction means that this directive can only be used as an HTML element and not for example an HTML attribute.
If you want to use it as an HTML attribute, change the restrict to return ‘A’ instead. The usage would then have to
be changed to:
<div my-widget>
<p>Hello World</p>
</div>
Whether you use the attribute or element mechanism will depend on your use case. Generally speaking one would
use the element mechanism to define a custom reusable component. The attribute mechanism would be used
whenever you want to “configure” some element or enhance it with more behavior. Other available options are
using the directive as a class attribute or a comment.
Other thoughts
This is a bad example because it uses jQuery for the steps that occur inside the custom directive.
Advanced Directives
So far, we have discussed common aspects of Directives. We dug into some common options, like template and
templateUrl, scope, restrict, and replace, and saw how to pass data to our directive to make it fully self-contained.
These cover 70–80% of the general use cases. The topics we cover in this portion address the other 20%, which deal
with getting a deeper understanding of the AngularJS life cycle.
In this discussion we first review the AngularJS life cycle in detail. We then go over the remaining options of the
directive definition object, including transclude, compile, controller, and require, as well as when to use them. With
all that covered, we dig into the common use case of extending ng-model with either creating new input directives or
creating our own custom validators. Finally, we see how we can integrate with third-party UI components like
graphs and charts.
[Sections to put here: lifecycle, transclusion, controllers, compile, priority, terminal]
Third-party integration
To be filled in
Best Practices
To be filled in
Page 12
Other Concerns
Using $location
The $location service parses the URL in the browser address bar (based on window.location) and makes the URL
available to your application. Changes to the URL in the address bar are reflected into the $location service and
changes to $location are reflected into the browser address bar.
The $location service:



Exposes the current URL in the browser address bar, so you can
o Watch and observe the URL.
o Change the URL.
Maintains synchronization between itself and the browser's URL when the user
o Changes the address in the browser's address bar.
o Clicks the back or forward button in the browser (or clicks a History link).
o Clicks on a link in the page.
Represents the URL object as a set of methods (protocol, host, port, path, search, hash).
Communicating between Scopes with Events
You can use $on, $emit, $broadcast to set up event sending and handling facilities that allow you to communicate to
other scope and controllers.
Internationalization
angular-translate is an AngularJS module that makes your life much easier when it comes to i18n and l10n including
lazy loading and pluralization.
Features: It provides components like filters and directives, asynchronous loading of i18n data, full pluralization
support through MessageFormat and much more!
Flexibility: angular-translate is very flexible. You can build your own loaders, storages or error handlers and extend
angular-translate to your needs!
Developing in AngularJS
Project Organization
You should seed your project with Yeoman, as that provides a good structure of directories for your app.
http://cliffmeyers.com/blog/2013/4/21/code-organization-angularjs-javascript
Running Your Application
Typically with Node.js
Tools
Good discussion of Batarang, Karma (test runner), and RequireJS.
Yeoman: Optimizing Your Workflow
There are quite a few tools that have sprung up to help optimize your workflow when developing web applications.
Yeoman is one such tool that boasts an impressive set of features, including:


Page 13
Lightning-fast scaffolding
Built-in preview server



Integrated package management
An awesome build process
Unit testing using PhantomJS
It also integrates nicely and extensively with AngularJS, which is one of the foremost reasons why we strongly
recommend using it for any AngularJS project.
Using the Resource plugin
This is based on http://www.sitepoint.com/creating-crud-app-minutes-angulars-resource/
Most Single Page Applications involve CRUD operations. If you are building CRUD operations using AngularJS,
then you can leverage the power of the $resource service. Built on the top of the $http service, Angular’s
$resource is a factory that lets you interact with RESTful backends easily. So, let’s explore $resource and use it to
implement CRUD operations in Angular.
Prerequisites
The $resource service doesn’t come bundled with the main Angular script. You need to download a separate file
called angular-resource.js and include it in your HTML page. The script can be downloaded from
http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.16/angular-resource.min.js.
Also, your main app module should declare a dependency on the ngResource module in order to use $resource. The
following example demonstrates how to do it:
angular.module('mainApp',['ngResource']); //mainApp is our main module
Getting Started
$resource
expects a classic RESTful backend.
The functionality is similar to Ruby on Rails ActiveRecord: what you end up is a quick way to perform the standard
operations (fetch a list of records, fetch one record, update one record, create one record, delete on record). It
doesn’t provide much flexibility, since its role is to provide a REST standard. Hence there is no status handling,
caching, complex query generation, table joining, etc.
How Does $resource Work?
To use $resource inside your controller/service you need to declare a dependency on $resource. The next step is
calling the $resource() function with your REST endpoint, as shown in the following example. This function call
returns a $resource class representation which can be used to interact with the REST backend.
angular.module('myApp.services').factory('Entry', function($resource) {
return $resource('/api/entries/:id'); // Note the full endpoint address
});
The result of the function call is a resource class object which has the following five methods by default:





get()
query()
save()
remove()
delete()
Alternatives
There is another service called Restangular, which has more advanced features and flexibility. See
http://sauceio.com/index.php/2014/07/angularjs-data-models-http-vs-resource-vs-restangular/
Page 14
Using the Ui-Router plugin
(this is gathered from http://www.funnyant.com/angularjs-ui-router/)
URL routing is a popular approach to matching the contents of a URL to specific functionality within a web
application. URL routes programmatically present specific content to users based on the URL that they are visiting.
It is a popular approach that has proven to be very effective.
Something that might not be obvious is that URL routing is also a finite state machine. When you configure the
routing for an app, you are laying out the various states the application can be in, and informing the application what
to display and do when a specific route is encountered.
AngularJS supplies URL routing by default. It is adequate, but also has some limitations.
In this case, ng-switch is swapping out div elements, but you can also use this approach to swap out templates
using ng-include.
Many developers do not like this option.
Why not?
 The ng-switch adds markup that could be confusing
 The state of the main content area is captured and stored on a model
 It feels like “logic in markup”
 If you go down the ng-include road, you need to remember to always put single quotes around your
template names. Developers forget this.
ui-router fully embraces the state-machine nature of a routing system. It allows you to define states, and transition
your application to those states. The real win is that it allows you to decouple nested states, and do some very
complicated layouts in an elegant way.
You need to think about your routing a bit differently, but once you get your head around the state-based approach, I
think you will like it.
Lessons Learned
1.
2.
3.
4.
5.
The ui-sref directive is the way to get from one state to another. It takes a new state name and optional
parameter list. In the Chrome browser inspector, you can see the href that is generated from the ui-sref,
which will be a valid url.
The next most common need is to highlight items on a menu that correspond to a navigation point. For
this, use ng-class=”{active: stateIncludes(‘games’)}” where stateInclude is a method in the
current controller (typically named MenuController or HeaderController). That function will call
$state.includes(name), which is a way to find if you are in a state and search the parent states.
$state.current is the new state
You can name a state “a.b” in which case “a” is the parent and “a.b” is the name, or define a state named
“b” and specify parent: a, in which case “a” is the parent, and “b” is the name. The former is preferred,
since then it is eaiser to have unique state names in a large system.
If you have a parent it can be abstract, which means that it cannot be transitioned to, but it must still have a
template.
There is another interesting facility providing a single state with two named views. This is useful when the subject
of your state is a single item and related data, so your state should probably revolve around that. You have
described two views, one which shows the item details, and another which shows other things, but the primary
subject is still the one item.
$stateProvider
.state('item', {
url: '/item/:itemID',
Page 15
views: {
detail: {
templateUrl: 'Scripts/app/item/ItemDetailTemplate.html',
controller: 'ItemDetailController as itemDetail'
}, related: {
templateUrl: 'Scripts/app/item/ItemListTemplate.html',
controller: 'ItemListController as itemList'
}
}
});
In your parent view, add two named ui-views, where the views defined above will plug into:
<div ui-view="related"></div>
<div ui-view="detail"></div>
Other parameters in the state definition include:
 controllerProvider – holds a function which will be called to return the controller or the controller class
name
 controllerAs – defines a name for the controller when used in code.
Using the resolve() facility in combination with ng-resource
The resolve() facility in a ui-router state provides a method that will be run when entering the state. Since we
typically are entering a state to display a specific data record that is to be found with ng-resource, these two
capabilities are often applied together. See http://www.jvandemo.com/how-to-resolve-angularjs-resources-with-uirouter/ for much of the key discussion.
See also http://odetocode.com/blogs/scott/archive/2014/05/20/using-resolve-in-angularjs-routes.aspx
You can use resolve to provide your controller with content or data that is custom to the state. resolve is an optional
map of dependencies which should be injected into the controller.
If any of these dependencies are promises, they will be resolved and converted to a value before the controller is
instantiated and the $stateChangeSuccess event is fired.
The resolve property is a map object. The map object contains key/value pairs of:
 key – {string}: a name of a dependency to be injected into the controller.
 factory - {string|function}:
o If string, then it is an alias for a service.
o Otherwise if function, then it is injected and the return value is treated as the dependency. If the result is
a promise, it is resolved before the controller is instantiated and its value is injected into the controller.
Here is an example:
$stateProvider.state('myState', {
resolve:{
// Example using function with simple return value.
// Since it's not a promise, it resolves immediately.
simpleObj: function(){
return {value: 'simple!'};
},
// Example using function with returned promise.
// This is the typical use case of resolve.
// You need to inject any services that you are
// using, e.g. $http in this example
promiseObj: function($http){
// $http returns a promise for the url data
return $http({method: 'GET', url: '/someUrl'});
}
});
Page 16
The first example is trival, the second is more interesting.
The resolve methods are executed before the state transition. Hence, if an exception occurs in the resolve methods,
the transition will be cancelled, with no obvious feedback. We haven’t found any discussion of this issue, but it
stands out as a valid one given the way that state transitions work.
Using the Bootstrap plugin
This repository contains a set of native AngularJS directives based on Bootstrap's markup and CSS. This can make it
easier to create a screen that contains Bootstrap elements, since you don’t write HTML and then have to look up the
CSS classes for Bootstrap. As a result no dependency on jQuery or Bootstrap's JavaScript is required. The only
required dependencies are:


AngularJS (requires AngularJS 1.2.x, tested with 1.2.16)
Bootstrap CSS (tested with version 3.1.1). This version of the library (0.12.1) works only with Bootstrap CSS in version 3.x. 0.8.0
is the last version of this library that supports Bootstrap CSS in version 2.3.x.
There is a file for each element of Bootstrap.
Example of using Collapse
<div ng-controller="CollapseDemoCtrl">
<button class="btn btn-default" ng-click="isCollapsed = !isCollapsed">Toggle collapse</button>
<hr>
<div collapse="isCollapsed">
<div class="well well-lg">Some content</div>
</div>
</div>
angular.module('ui.bootstrap.demo').controller('CollapseDemoCtrl', function ($scope) {
$scope.isCollapsed = false;
});
Example of using Accordion
<accordion close-others="oneAtATime">
<accordion-group heading="Static Header, initially expanded" is-open="status.isFirstOpen"
is-disabled="status.isFirstDisabled">
This content is straight in the template.
</accordion-group>
<accordion-group heading="{{group.title}}" ng-repeat="group in groups">
{{group.content}}
</accordion-group>
</accordion>
Here you write a series of accordion-groups within the accordion element. Each group can have a heading, and then
has body content.
In the above example, an ng-repeat directive is used to fetch the each group’s header and content from the Angular
$state.
Using the Flash service
This is from http://fdietz.github.io/recipes-with-angular-js/common-user-interface-patterns/displaying-a-flashnotice-failure-message.html
Page 17
It allows you to have controller code post a notification message, such as an error message, which only applies to the
next-processed request. It is similar in concept to the flash message state in Ruby on Rails or Java Spring. The
main code looks like:
app.factory("flash", function($rootScope) {
var queue = [];
var currentMessage = "";
$rootScope.$on("$routeChangeSuccess", function() {
currentMessage = queue.shift() || "";
});
return {
setMessage: function(message) {
queue.push(message);
},
getMessage: function() {
return currentMessage;
}
};
});
We have recently been using this and injecting the flash service into most of the controllers. Once injected, call
“flash.setMessage()”. In your view, code:
<div class="alert" ng-show="flash.getMessage()">
<b>Alert!</b>
<p>{{flash.getMessage()}}</p>
</div>
Notice that you can call getMessage() multiple times without losing the current message, since it only gets taken off
the queue upon change ui-router state.
Other Modules of Interest
Cookies
AngularJS provides you with a nice $cookie and $cookieStore API to work with cookies. Both services play nice
with HTML5 cookies, in that they use HTML5 APIs when available, and default to working with document.cookies
when they are not. Either way, you get to use the same API calls.
Let’s take a look at the $cookies service first. $cookies is simply an object. It has keys and values. Adding a key
and its corresponding value to the object adds the information to the cookie, and removing it from the object deletes
that particular cookie. It’s as simple as that.
Loader
A script loader for AngularJS that perform AMD-like script injection without the need for special syntax.
Rationale: Suppose you have a JavaScript file for every module. And you have a lot of scripts with specific tasks;
directives, factories, utility functions. You name it.
Loader gives us a way to define dependencies, which will be loaded when your JavaScript is loaded.
As angular-seed project shows us, Angular loader does not have any specific api, you just put it on top of your index
file (so that it's executed first) and than proceed to load you application files anyway you prefer.
Page 18
See also the ocLazyLoad module (below), for an improved version of this capability.
Sanitizing
AngularJS takes its security seriously, and tries to make all efforts to ensure that most attack vectors are minimized.
One of the attack vectors revolves around the injection of unsafe HTML content into your webpage and using that to
trigger a cross-site or injection attack.
There is a module called angular-sanitize which carries out this process by parsing the HTML into tokens. All safe
tokens (from a whitelist) are then serialized back to properly escaped html string. This means that no unsafe input
can make it into the returned string, however, since our parser is more strict than a typical browser parser, it's
possible that some obscure input, which would be recognized as valid HTML by a browser, won't make it through
the sanitizer. The input may also contain SVG markup. The whitelist is configured using the
functions aHrefSanitizationWhitelist andimgSrcSanitizationWhitelist of $compileProvider.
This capability is used by many other plugins, which generate HTML from provided data, and since that data might
by entered by a rogue user, the sanitization process is critical. So this is one of the most commonly used modules.
Cheatsheet and Recipes
Wrapping a jQuery DatePicker
File upload
Using SocketIO
Pagination
Working with Servers and Login
Third-party Plugins/Directives of Interest
UI-Utils
A collection of useful utility functions. See http://angular-ui.github.io/ui-utils/
Depends upon angular-sanitize for several display support functions.
Event binder: allows you to define event handlers on elements.
Format: Replace tokens in a string in a variety of ways. Often useful for internationalization.
Mask: input mask, handy for validation
Fragment – Fragment support has two primary uses: (1) it serves as a drop in replacement for jQuery.load(), which
permits a subset of a requested document to be selected, and (2) because some people want to put multiple templates
into a single file and they need a way to select which specific fragment to use.
Scrollfix:
Validate:
Unique: this helps generate set of unique values for use in ui-select.
UI-Select
AngularJS-native version of Select2 and Selectize. API at https://github.com/angular-ui/ui-select/wiki/ui-select
Page 19
Depends upon UI-Utils for the highlight filter.





Search and select – allow you to choose from a set of partial matches. Very handy for creating filters.
Support themes from Select2 (default theme) and Selectize (default, Bootstrap 2 & 3 themes)
Keyboard support
jQuery not required (except for old browsers)
Small code base: 250 lines of JavaScript vs 20 KB for select2.min.js
Example:
<ui-select ng-model="address.selected"
theme="bootstrap"
ng-disabled="disabled"
reset-search-input="false"
style="width: 300px;">
<match placeholder="Enter an address...">{{$select.selected.formatted_address}}</match>
<choices repeat="address in addresses track by $index"
refresh="refreshAddresses($select.search)"
refresh-delay="0">
<div ng-bind-html="address.formatted_address | highlight: $select.search"></div>
</choices>
</ui-select>
This goes quite a ways toward the goal of having Angular provide “html” for applications. Most of the above
features would require some complex JavaScript being coded in JQuery and attached to the DOM. Hence you feel
that <ui-select> gives a programming-based model for selection lists, rather than just an html element.
ocLazyLoad
Load modules on demand (lazy load) in AngularJS. See http://ngmodules.org/modules/ocLazyLoad
Key features







Dependencies are automatically loaded
Debugger friendly (no eval code)
The ability to mix normal boot and load on demand
Load via the service or the directive
Use the embedded async loader or use your own (requireJS, ...)
Load js (angular or not) / css / templates files
Compatible with AngularJS 1.2.x/1.3.x/1.4.x
Usage



Put ocLazyLoad.js into your project
Add the module oc.lazyLoad to your application (you can install it with bower install oclazyload or npm install oclazyload)
Load on demand: With $ocLazyLoad you can load angular modules, but if you want to load any component (controllers / services / filters / ...)
without defining a new module it's entirely possible (just make sure that you define this component within an existing module).
There are multiple ways to use
$ocLazyLoad
to load your files, just choose the one that you prefer.
Grid
http://angular-ui.github.io/ng-grid/ See our document “Notes on NG-Grid and UI-Grid”.
Related Tools
Yeoman – the web’s scaffolding tool for modern webapps. Will help generate the structure of an app.
Bower – a package-loading tool for client side application, just as npm is a server-side tool for a similar purpose.
See our document “Notes on Bower”.
Grunt – a runner environment
Gulp – a replacement for Grunt
Page 20
Questions
Extra level of evaluation
http://stackoverflow.com/questions/21487617/how-do-i-make-angular-js-reevaluate-recompile-inner-html
Appendix A: Learning Examples Created
These examples are self-contained apps that are serviced by an Apache server, and have no backend. For examples
with a backend, we tend to use Node.js. See our document “Notes on Node.js and Express.js”.
There are some related examples with different backends, such as one with a Rails backend, and one with a Scalatra
backend.
ANG01
Allows you to create and maintain a list of character names. Includes use of Bootstrap 3.3.2. Based on example 0205 in the “Angular Unraveled” book.
ANG02
Expands upon ANG01 to be a larger shopping cart application. Includes use of Bootstrap 3.3.2. Includes uses of
prices, currency-formatted displays, and calculations.
ANG03
Uses the ng-grid plugin/directive. Includes use of Bootstrap 3.3.4. See our document “Notes on NG-Grid and UIGrid”. Also uses Wijmo Grid. See our document “Notes on Wijmo 5”.
ANG04
This project is derived from the material at www.angularcourse.com
The code is at https://www.dropbox.com/sh/ydmsb7e56mdgb7p/AAA7dYJ5JtZF3tMe6Xi-kfIca?dl=0
A nearly-finished version is on GitHub at https://github.com/sergioschuler/wait-and-eat
There is a running version at http://www.whatzhub.com/waitandeat
Lessons 1 through 5 were mostly setup. There were lessons specific to Mac and to Windows. The basic steps
included setting up a Python app to act as a web server. We used WAMP instead.
Lesson 6: Review of the starter code. The `ngRoute` module provides routing and deeplinking services and
directives for angular apps. This is an optional module, but one that is very commonly used (it is described above).
Lesson 7: Add a route, template, and controller for the landing page. Cleanup in the index.html file.
Lesson 8: Install bootstrap and populate the top menu.
Lesson 9: Populate the landing page.
Lesson 10: Start the waitlist page. Create the partial, and the controller. Most empty content at this point
Lesson 11: HTML Waiting list form. Create the form.
Lesson 12: Get the form to submit data. In this case, we are populating a static list within the Controller class.
Lesson 13: Connect to Firebase. This covers setting up your Firebase account, adding the needed JS libraries to
app, creating the Firebase connection, and reading from it / adding to it.
Page 21
Lesson 14: Use ng-repeat to show parties in a table. A very important concept!
Lesson 15: Implement the remove-party feature. The lesson’s implementation uses the collection management
facilities of Firebase (there is also a discussion of orderByPriority). Our implementation simply removes from a
JavaScript list.
Lesson 16: Write the code for the SMS messages. This creates the event handler, and creates a section in the
Firebase storage for text messages (then we re-organized the event data).
Lesson 17: Setup Twilio. This lesson all takes place in Twilio.
Lesson 18: Set up Zapier. This lesson all takes place in Zapier, and you create an action handler that listens for a
new child record in Firebase, then triggers Twilio.
Lesson 19: Customize the text message. Add party name and size by passing more fields into the backend handling
in Twilio and Zapier. This means passing the party object into, to make a change to it. We create a new object
containing the number, name and size into sendTextMessage instead of the phone number into the backend.
Lesson 20: Mark-as-done. Map a text box to a field in the database. This discusses use of ng-change.
Lesson 21: Mark party as notified. Short lesson because all we do is add another field to the record and display.
Lesson 22: New user registration. This begins a new aspect of the project, which is user-focused. Very long lesson,
but it introduces the facilities within Firebase for managing users, includes a new library, defines a new controller,
and creates a new partial. At the end, we can register and our user information will be visible in the Firebase admin
console.
Lesson 23: Logging in. Allow existing users to log in. This adds an additional partial, and connects the different
actions in the controller so that the application state is changed when the user logs in. The controller for the new
partial is shared with the register partial.
Lesson 24: Logging out. Add a logout method to the AuthController, and trigger it from the navigation bar.
Lesson 25: Using $location. This allows your code to forward the application flow to another part of the code, such
as from one screen to another.
Lesson 26: Building a service. Reduce repetitive code by creating a service for FIREBASE_URL. Lesson does not
have a lot of code, but introduces an important concept. The example is a value service. There are several types of
services, he suggests we focus on value services and factory services.
Lesson 27: Create an authentication service. Start moving code from controllers into common service. This lesson
was mostly code migration.
Lesson 28: More on the auth service. At this point we finished up the work started in Lesson 27. The
AuthController is now very simple.
Lesson 29: Showing and hiding buttons. At 10 minutes, this is one of the longer lessons, but it introduces
$rootScope, ng-show, and ng-hide.
Lesson 30: Build the partyService. Move party features from the WaitlistController into a new service.
Lesson 31: Build the textMessageService. This also takes code out of the WaitlistController.
Lesson 32: Build the dataService. Short video, avoid repeating similar lines where we create a Firebase object.
Page 22
Lesson 33: Save unique data for user. At 12:59 in length this is a long one. We are going to save data in separate
places within Firebase for each user.
Lesson 34: Refetch unique data for user. Another long one at 12:00 in length. Simple change but a great deal of
discussion.
Lesson 35: Fix the textMessageService. Since this modifies a party’s data, we need to update it.
Lesson 36: Registration emails. Email new users when they sign up. Add an ‘emails’ object location in Firebase,
and have Zapier watch for changes to this. Most of the work of this lesson was in Zapier.
Lesson 37: Security. Use Firebase security rules to set rules on who can read and write to different locations in our
Firebase. Prior to this, the application was open. At 21:00 in length, this lesson is the longest in the whole set.
Most of the work is done in Firebase, and then access codes are copied to the application. There is even a simulator
in the Firebase system to check the behavior of the rules that you have defined.
Lesson 38: Launch! No more localhost. This is 16 minutes long, and it talks about how to deploy your app and the
various hosting options for it. The options include Google App Engine, Apache, Node.js, etc. There are even
options to host your static resources on Firebase.
ANG05
This is based on the “GutHub” recipe-management application discussed in chapter 4 of the AngularJS book. It is a
program that uses Node.js and Express.js on the back end, and then has Angular on the front end. There is no
database persistence at this point, it simply stores content into a global on the Node.js side.
There is a sidebar on the left that brings up two views: Recipe List, and New Recipe.
ANG06
Provides a demonstration of the ui-routing plugin, and the resource plugin, as well as bootstrap plugin. Based on
document from http://www.sitepoint.com/creating-crud-app-minutes-angulars-resource/, but greatly changed during
mid-April to have three related entities (games, episodes, objectives) and navigation. This has a Node-based backend and is writing to a MySQL database on AWS. Also a set of screens to demonstrate angular features such as uibootstrap and ui-select.
ANG07
Work area for using several screens, ui-router, bootstrap, and grids. Data model is account, campaign, adGroup.
Also a set of screens to demonstrate angular features such as ui-bootstrap and ui-select. Now uses only Wijmo, and
is a test case for using ui-router-extensions.
ANG08
This is a work area for layout operations, such as north-south-east-west layouts. Pretty simple right now.
Page 23
Download