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