SPA AngularJS Draft

190
Modern Web Application Development Single Page Application Development using AngularJS JavaScript Overview Static Page: The web isn’t always as responsive as it could be. You would expect entering data in a web page would generate some sort of response… but nothing happened. Interaction is two-way communication. But JavaScript Talks Back. JS turns a web page into an interactive. JavaScript brings a web page to life by allowing it to respond to a user’s input. JS can turn a web page interactive application as opposed to a static, life less page. Example:

description

Angular Beginner

Transcript of SPA AngularJS Draft

Page 1: SPA AngularJS Draft

Modern Web Application DevelopmentSingle Page Application Development using AngularJS

JavaScript OverviewStatic Page: The web isn’t always as responsive as it could be. You would expect entering data in a web page would generate some sort of response… but nothing happened.

Interaction is two-way communication.But JavaScript Talks Back. JS turns a web page into an interactive. JavaScript brings a web page to life by allowing it to respond to a user’s input. JS can turn a web page interactive application as opposed to a static, life less page.

Example:

Page 2: SPA AngularJS Draft

Modern Web Page JS sits with HTML and CSS as one of three pieces of Modern Web Page Construction.

HTML provides the Structure CSS adds the Style JS puts the action (injection functional sizzle, allowing the page to take action). JS springs

into action when the user asks the page to perform a task.

Your Web browser can handle HTML, CSS and JavaScript.

Alerting the user the with a function. JS alert() function and passing it the text you want to display.JS alert() is a pop-up window, or box, that you can use to display information to the user.

Functions are reusable piece of code that perform common tasks.

Data Types:JS uses three basic data types: text, number, and boolean.var variablename = initial value; // variable names use CamelCase

lowerCamelCase is used to name multiWord variables. the first word is all lowercase, butadditional words are mixed-case.

const constantname = constant value;

A piece of data is undefined when it has no value.X = NaN; NaN is a value that isn’t a number even though you’re expecting the value to be one.parseInt() and parseFloat() converts text to a number.

Use getElementById() to grab the data from your Web page. The key to accessing a web page element with JavaScript is the id attribute of the HTML tag:<input type="text" id="cakedonuts" name="cakedonuts" />The id attribute is what you use to access the form field in JavaScript codeThe id attribute uniquely identifies any element in a page. The name attribute uniquely identifies a field within a form.

isNan() function

Client’s window width and heightThe client window is only the part of the browser window that displays a web page.document.body.clientWidthdocument.body.clientHeight

Script Life Cycle1. The browser is launched2. User enters URL in address bar3. The page is loaded from the web server – HTML, CSS, JS and all4. The onLoad event fires, JavaScript variables are created and initiated.5. The user closes the browser or reloads the page6. The script stops, JS cleans up all variables, and the page is closed.

Scope of variables:Global Variables data can be seen everywhere in a script

Page 3: SPA AngularJS Draft

Local Variables limited to specific block of code, such as a function

Arrays stores multiple pieces of data in a single place.var showtime = new Array();showtime[0] = “12:30”;

var showTime = [“12:30”, “2:45”, “5:00”, “7:00”];

Functionsfunction name() { body }Passing information to functions:function name(arguments) { body}Returning data from functions:return value;Callback Functions: Which are called by the browser, instead of your own code. The most common use of callback functions is in handling events.<body onload=”initSeats()”><img …. Onclick=”showSeatStatus(26)”>Using Function References You can assign a function reference directly in a JS code. window.onload = initSeats; // There are no parantheses following the function name because you don’t want to run the function; you just want to reference it.Anonymous Functions: It is a nameless function that handles the event.window.load = function() { initSeats();}document.getElementById(“seat26”).onclick = function(evt) { showStatus(26);}An event object is passed into event handler, in this case evt argument. The event object contains information specific to each different event.

Regular Expressions A regular expression is used to match patterns in text.Pattern involves physical attributes of a person. Pattern = Tall, no glasses, short hair.The pattern describes physical properties of a person that are then matched against actual people. Regular expressions allow you to do the same kind of pattern matching with strings.A text pattern involves a certain sequence of characters.Pattern = ##### This pattern involves a sequence of exactly five numeric digits.

All Regular Expressions are enclosed by forward slashes. / expression /Within the expression, a collection of special symbols known as metacharacters are used in conjunction with letters and numbers.(dot) . Any character other than a new line\d Any numeric digit\w Any alphanumeric character\s A whitespace character

Page 4: SPA AngularJS Draft

^ String must begin with the pattern (The string being matched can’t have any text preceding the pattern)$ The String must end with the pattern. (The pattern must be the very last characters in the string).

Examples:/./ (Any Single Character) “A” or “%” or “7”/\w/ (Any Alphanumeric) “A” or “7” /\d/ (A single digit) “7” or “2nite” or “catch22”/^\d/ (One digit at the beginning of a string) “7” or “007” or “2nite”/\d\d$/ (Two digits at the end of a string) “catch22”/\d\d\d/ (Three digits in a row) “007”/^cat/ (cat appearing at the beginning of a string) “catch22”/cat$/ (cat appearing at the end of a string) “incat”/^\d\d\d\d\d-\d\d\d\d$/

Quantifiers precede within a regular expression, and provide control over how many times a sub-pattern appears in a pattern.{n} sub-pattern must appear exactly n times in a row.* sub-pattern is optional and can appear any number of times? sub-pattern is optional, but can only appear once if does appear+ sub-pattern is required, and can appear any number of times( ) used to group together sub-patterns much as you group together mathematical expns

Examples/^\d{5}-\d{4}$/ A zip code pattern./\w*/ Matches any number of alphanumeric characters, including an empty string/.+/ Any character must appear one or more times… matches a non-empty string/(Hot)? ?Donuts/ Matches either “Donuts” or “Hot Donuts”

Validating data with regular expressionvar regex = /^\d{5}$/;The regular expression matches a 5-digit ZIP code. $: This object literal automatically creates a RegEx object.If(!regex.test(inputField.value))

// The zip code is invalid

Date pattern: MM/DD/YYYY or MM/DD/YY /^\d{2}\/\d{2}\/\d{2,4}$/Phone Number pattern: \^\d{3}-\d{3}-\d{4}$/Email: /^\w+@\w+\.\w{2,3}$/

Creating space with DIV In order to display description on the page instead of alert box, we first need to define a physical area on the page as an HTML element. <div> should work fine for description text appears as its own paragraph.<div id=”sometext”></div> innerHTML is used to set the content on the page.document.getElementById(“sometext”).innerHTML = “You are <strong> not </strong> alone”;

The DOM sees a web page as a hierarchical tree of nodes. Your page is a collection of DOM nodes. DOM nodes are classified according to their node types.

Page 5: SPA AngularJS Draft

Climbing the DOM tree with properties:nodeValue The value stored in a node, only for text and attribute nodes (note elements)nodeType The type of a node, such as DOCUMENT or TEXT, but expressed as a number.childNodes Arrays containing all of the child nodes beneath a node, in the order that the nodes appear in the HTML code.firstChild The first child node beneath a node.lastChild The last child node beneath a node.Document.getElementById(“sometext”).nodeValue

Objects link variables (properties) and functions (methods) together inside a storage container.The dot operator references a property or method from an objectA constructor is responsible for creating an object. Every custom object requires its own constructor, which is named the same as the object.Example: Write a constructor for a Blog object that creates and initializes properties for the date and body text of a blog entry.Function Blog(body, date) { this.body = body; this.date = date;}var blogEntry = new Blog(“Got the new cube”, “08/04/2013”);

An Object class is a template, while an object instance is the thing created from the template.

Defining Objects: function Card(name, address, work, home) { this.name = name;this.address = address;this.workphone = work;this.homephone=home;}Defining a Object methodfunction PrintCard() { line1 = "Name: "+ this.name + "<br>\n"; line2 = "Address: " + this.address + "<br>\n"; line3 = "Work Phone: " + this.workphone + "<br>\n"; line4 = "Home Phone: " + this.homephone + "<hr>\n"; document.write(line1, line2, line3, line4);}

You now have a function that prints a card, but it isn't officially a method of the Card object. The last thing you need to do is make PrintCard() part of the function definition for Card objects. Here is the modified function definition:

function Card(name,address,work,home) { this.name = name; this.address = address; this.workphone = work; this.homephone = home; this.PrintCard = PrintCard;}

The following statement creates a new Card object called tom:

Page 6: SPA AngularJS Draft

tom = new Card("Tom Jones", "123 Elm Street", "555-1234", "555-9876");tom.PrintCard();

Extending Built-In Objects:

JavaScript includes a feature that enables you to extend the definitions of built-in objects. For example, if you think the String object doesn't quite fit your needs, you can extend it, adding a new property or method. This might be very useful if you were creating a large script that used many strings.

You can add both properties and methods to an existing object by using the prototype keyword. (A prototype is another name for an object's definition, or constructor function.) The prototype keyword enables you to change the definition of an object outside its constructor function.

As an example, let's add a method to the String object definition. You will create a method called heading, which converts a string into an HTML heading. The following statement defines a string called title:

title = "Fred's Home Page";

This statement would output the contents of the title string as an HTML level 1 heading:

document.write(title.heading(1));

Listing 6.4 adds a heading method to the String object definition that will display the string as a heading, and then displays three headings using the method.

Listing 6.4. Adding a Method to the String Object

<html><head><title>Test of heading method</title></head><body><script LANGUAGE="JavaScript" type="text/javascript">function addhead (level) { html = "H" + level; text = this.toString(); start = "<" + html + ">"; stop = "</" + html + ">"; return start + text + stop;}String.prototype.heading = addhead;document.write ("This is a heading 1".heading(1));document.write ("This is a heading 2".heading(2));document.write ("This is a heading 3".heading(3));</script></body></html>

Page 7: SPA AngularJS Draft

First, you define the addhead() function, which will serve as the new string method. It accepts a number to specify the heading level. The start and stop variables are used to store the HTML "begin header" and "end header" tags, such as <h1> and </h1>.

After the function is defined, use the prototype keyword to add it as a method of the String object. You can then use this method on any String object or, in fact, any JavaScript string. This is demonstrated by the last three statements, which display quoted text strings as level 1, 2, and 3 headers.

function Name(first,last) { this.first = first; this.last = last;}

You can add additional properties to an object you have created just by assigning them:

Fred.middle = "Clarence";

Properties you add this way apply only to that instance of the object, not to all objects of the type. A more permanent approach is to use the prototype keyword, which adds a property to an object's prototype (definition). This means that any future object of the type will include this property. You can include a default value:

Name.prototype.title = "Citizen";

Object Oriented Java ScriptPrototype-based programming is a style of object-oriented programming in which classes are not present, and behavior reuse (known as inheritance in class-based languages) is accomplished through a process of decorating existing objects which serve as prototypes.This model is also known as class-less, prototype-oriented or instance-based programming.Java Script Object oriented programming – Custom ObjectThe Class: JS is a prototype-based language which contains no class statement, such as is found in C++ or Java. Instead JS uses functions as classes. Defining a class is easy as defining a function.Function Person() { }The Object (Class Instance) To create a new instance, use new operator.var p1 = new Person(); var p2 = new Person();The constructor is called at the moment of instantiation.The Property properties are variables contained in the class. Properties defined within a class is done by keyword this, which refers to the current object.function Person(gender) { this.gender = gender; alert(‘Person instantiated’);} var p1 = new Person(‘Male’); alert(‘Person 1 is a ‘ + p1.gender);The Methods are functions and they are defined as functions. To define a method, assign a function to a named property of the class’s prototype property; the name that the function is assigned to is the name that the method is called by on the object.Person.prototype.sayHello = function() { Alert(‘Hello method..’);}

Page 8: SPA AngularJS Draft

In JavaScript methods are regular function objects that are bound to a class/object as a property which means they can be invoked "out of the context". Consider the following example code:

function Person(gender) { this.gender = gender;}

Person.prototype.sayGender = function(){ alert(this.gender);};

var person1 = new Person('Male');var genderTeller = person1.sayGender;

person1.sayGender(); // alerts 'Male'genderTeller(); // alerts undefinedalert(genderTeller === person1.sayGender); // alerts truealert(genderTeller === Person.prototype.sayGender); // alerts trueThis example demonstrates many concepts at once. It shows that there are no "per-object methods" in JavaScript since all references to the method point to the exact same function, the one we have defined in the first place on the prototype. JavaScript "binds" the current "object context" to the special "this" variable when a function is invoked as a method(or property to be exact) of an object. This is equal to calling the function object's "call" method as follows:

genderTeller.call(person1); //alerts 'Male'

Inheritance

Inheritance is a way to create a class as a specialized version of one or more classes (JavaScript only supports single class inheritance). The specialized class is commonly called the child, and the other class is commonly called the parent. In JavaScript you do this by assigning an instance of the parent class to the child class, and then specializing it. In modern browsers you can also use Object.create to implement inheritance.

JavaScript does not detect the child class prototype.constructor see Core JavaScript 1.5 Reference:Global Objects:Object:prototype property, so we must state that manually.In the example below, we define the class Student as a child class of Person. Then we redefine the sayHello() method and add the sayGoodBye() method.

// define the Person Classfunction Person() {}

Person.prototype.walk = function(){ alert ('I am walking!');};Person.prototype.sayHello = function(){ alert ('hello');};

// define the Student class

Page 9: SPA AngularJS Draft

function Student() { // Call the parent constructor Person.call(this);}

// inherit PersonStudent.prototype = new Person();

// correct the constructor pointer because it points to PersonStudent.prototype.constructor = Student; // replace the sayHello methodStudent.prototype.sayHello = function(){ alert('hi, I am a student');}

// add sayGoodBye methodStudent.prototype.sayGoodBye = function(){ alert('goodBye');}

var student1 = new Student();student1.sayHello();student1.walk();student1.sayGoodBye();

// check inheritancealert(student1 instanceof Person); // true alert(student1 instanceof Student); // trueUsing Object.create the inheritance line would instead be:

Student.prototype = Object.create(Person.prototype);

Page 10: SPA AngularJS Draft

AngularJS AngularJS is a client-side JavaScript framework It's used to build web applications It is prescriptive Makes creating a user interface (UI) easier through data-binding It helps organize and architect an application it has custom elements and attributes it uses dependency injection

What is AngularJS?AngularJS is a framework that helps you build front-ends for web-based applications.AngularJS is a prescriptive client-side JavaScript framework used to make single-page web apps.

Note:Prescriptive Architecture vs. Descriptive ArchitectureA system’s prescriptive architecture captures the design decisions made prior to the system’s construction. It is the as-conceived or as-intended architecture.A system’s descriptive architecture describes how the system has been built. It is the as-implemented or as-realized architecture.

AngularJS is prescriptive in the sense that it has a recommended way of building web apps. It has its own spin on the ubiquitous Model View Controller (MVC) pattern that is especially well suited for JavaScript. In this way, Angular is prescribing a way for you to divide your application up into smaller parts.AngularJS is a framework that runs in the web browser.

AngularJS is for single page apps, meaning the browser only loads the page once, but then makes asynchronous calls to the server to fetch new information. Here asynchronous means that the application can continue to function without having to stop and wait for the server to respond.

Core Features of AngularJSTwo-way Data Binding: Let's say you have a form to store user contact info and you want to update the addresses input box when data is returned from the server. You could do the following:<span id="yourName"></span>document.getElementById('yourName')[0].text = 'bob';You manually seek to the element you want to change, calling a long, awkward series of DOM methods.You also have to make this call every time something causes the address to change.If we take the same example above and use data-binding we accomplish the same thing but faster. Here's our example with data-binding:<span>{{yourName}}</span>var yourName = 'bob';

Model View Whatever (MVW): MVC is a pattern for dividing an application intodifferent parts (called Model, View, and Controller), each with distinct responsibilities.AngularJS as a "Model View Whatever" framework. In AngularJS, the View is simply your HTML with the AngularJS syntax compiled into it. Once the initial compilation cycle completes, the View can then bind to the object which is essentially the ViewModel.

Page 11: SPA AngularJS Draft

HTML Templates: HTML templates are useful when you want to predefine a layout with dynamic sections to be filled in it is connected with an appropriate data structure.An example of this would be if you wanted to repeat the same DOM element over and over in a page such as a list or a table. You would define what you want a single row to look like and then attach a data structure, such as a JavaScript array, to it. The template would repeat each row for as many items in the array filling in each instance with the values of that current array item.There are plenty of templating libraries out there but most of them require you learn a new syntax.AngularJS templates are HTML and are validated by the browser just like the rest of the HTML in the page.

Deep Linking:

Dependency Injection: Defined a function that accepts a parameter you have leveraged dependency injection. You are injecting something that your function depends on to complete its work.Consider this code:Defining functions without DIfunction a () {return 5;}function b () {return a() + 1;}console.log(b());

Defining functions with DIservice('a', function () {return 5;});service('b', function (a) {return a() + 5;});

Page 12: SPA AngularJS Draft

service('main', function (b) {console.log(b());});

Overriding with DI// swap out 'b' easily by redefining it in another file:service('b', function (a) {return 1; // this is a test value});

Directives: it allows you to extend HTML to do some really powerful things.Directives provide the perfect way to merge the declarative nature of HTML and the functional nature of JavaScript into one place.Let's say you're writing an application that has a dropdown.<div class="container"><div class="inner"><ul><li>Item<div class="subsection">item 2</div></li></ul></div></div>

You can use a directive to make a shortcut so you only have to type:<dropdown><item>Item 1<subitem>Item 2</subitem></item></dropdown>

TESTABLE: How do you REALLY know your app works? The answer is "by writing tests," but it's often more complicated than that.AngularJS makes it easy to write unit tests.Mocking out parts of your application, you can test each feature in isolation.Angular also makes it easy to write integration tests that ensure your whole stack is functioning as expected.

A quick recap: AnguarJS has many benefits and features. If you are were to pick three things to remember about it, they are data-binding, testability, and "just JavaScript." Or consider the old way of writing web-apps with event handlers and DOM mutations, and think of how much easier it would make your development process to use Angular instead.

Hello Angular Example we're going to make a "Hello ___" program, where we have an input box that fills the blank in with whatever we type into the box.

As you type into the input box, The line "Hello ___" gets filled in with the contents of the input box.

Page 13: SPA AngularJS Draft

<body ng-app="helloApp"><div ng-controller="HelloCtrl"><p>{{greeting}} {{person}}</p><input ng-model="person"></div><script>angular.module('helloApp').controller('HelloCtrl', function ($scope) {$scope.greeting = 'Hello';$scope.person = 'World';});</script></body>

a Single Page Application is one in which we have a shell page and we can load multiple views into that.So a traditional app, as you know you typically blink and load everything again. It’s not very efficient on the bandwidth, especially in the mobile world.In a SPA we can load the initial content upfront and then the different views or the little kind of mini- web pages can be loaded on the fly and embedded into the shell.

The challenges with SPA:1. DOM Manipulation2. History3. Module Loading4. Routing5. Caching6. Object Modeling

Page 14: SPA AngularJS Draft

7. Data Binding8. AJAX / Promises9. View Loading

Angular JS is a fully featured SPA Framework:Data Binding, MVC, Routing, Testing, jqLite, Templates, History, Factories, ViewModel, Controllers, Views, Directives, Services, Dependency Injection, Validation

Getting Started with AngularJS1. Download from angularjs.org2. Import the angular.js file in your web page

<script src=”angular.min.js”></script> Using Directives and Databinding Syntax:Directives start with ng i.e. ng-app, ng-modelng-model does is behind the scenes it’s going to add a property up in the memory called “name” into what’s called “the scope”.

Include the ng-app

Include the ng-model

Bind to that model. <html ng-app><body> Working with Model directive and Data Binding <input type="text" ng-model="name"/> {{name}}</body>

Working with Init and Repeat directiveWe’ve now initialised our data with the ng-init.

We’re going to iterate through our data with the ng-repeat

We simply give it the name and it’s going to put that name into the variable when we bind to it

<div ng-init="names=['Sarath', 'Chandu', 'Teju', 'Devi']"> <ul>

<li ng-repeat="myname in names">{{myname}}</li> </ul> </div>ng-init is used to initialize data to bind to and display.ng-repeat which will simply loop through all the names, and then data-bind or apply the value into the <li>. For each myname in the names variable write out the myname. Myname is just a variable.Try initializing data in body. i.e. <body ng-init=….>

Repeat with Objects: Instead of having array of strings, I have an array of objects.<div ng-init="customers=[{name:'John Smith', city: 'Phoenix'}, {name:'John Doe', city: 'New York'}, {name:'Jane Doe', city: 'San Fransisco'}]"> <ul>

<li ng-repeat="cust in customers">{{cust.name}} - {{cust.city}}</li> </ul> </div>

Page 15: SPA AngularJS Draft

Filteringlet’s do a filter by and whenever they type a name instead of data-binding to it I want to use it as a filter. So we’re going to filter by the name property that’s in our model.<div ng-init="customers=[{name:'John Smith', city: 'Phoenix'}, {name:'John Doe', city: 'New York'}, {name:'Jane Doe', city: 'San Fransisco'}]"> Enter Name: <input type="text" ng-model="name">{{name}} <ul>

<li ng-repeat="cust in customers | filter:name">{{cust.name}} - {{cust.city}}</li> </ul> </div>We can also use “orderBy”. do another pipe and “orderBy” and then in quotes give it the property.<li ng-repeat="cust in customers | filter:name | orderBy:'city'">{{cust.name}} - {{cust.city}}</li>

Let’s say we wanted the name to be uppercase and the city to be lowercase.<li ng-repeat="cust in customers | filter:name | orderBy:'city'">{{cust.name | uppercase}} - {{cust.city | lowercase}}</li>

Views, Controllers and Scope

You should be able to define a controller that you can bind to different views. Maybe you have a mobile view, you have a desktop view or whatever it may be.<div ng-controller="SimpleController">

<ul><li ng-repeat="cust in customers">{{cust.name + ' ' + cust.city}}</li>

</ul> </div>

<script>function SimpleController($scope) {

$scope.customers = [{name: 'Dave Jones', city: 'Phoenix'}, {name:'Jamie Riley', city:'New York'},{name: 'Heedy Wahlin', city: 'Atlanta'}, {name:'Thomas Winter', city: 'Seattle'}]

} </script>An ng-controller, SimpleController. That’ll automatically tie in this.

Page 16: SPA AngularJS Draft

In the parameter signature. You’ll see that we pass $scope. This is dependency injection that’s built into AngularJS.When this controller gets used, will automatically inject a scope object in. You’ll see that from there we’ll take that object and add in a property onto it called customers which is simply an array of object literals.What this controller can do then is serve as the source of the data for the view but the controller again shouldn’t know anything about the view, so how would we possibly communicate customers over? Well that’s why we’re injecting scope. Scope is to be that view between the controller and the view.If we come up to our view up here the scope gets injected and then that scope is going to be automatically bound into the view once the view knows about this controller.When this [the controller] gets initialised the scope gets passed in but it’s initially empty. Well we’re going to add a customers property. What’s going to happen then is this controller will be used by the view. The controller itself though isn’t going to be called – it’s going to go through the scope. The scope itself is implicitly available – in this case to the entire div: from the start of the div to the end of the div. Now look at the ng-repeat here. It’s the same thing I did earlier in the demo, except in this case it’s binding to the scope’s customers property

What’s going to happen now is the view, because it knows about the controller, automatically gets passed the scope. Angular does that kind of behind the scenes – it just happens automatically. We’re going to then control in our view what properties we want to bind to. In this case we’re going to bind to the customers.From here it’s standard data binding like we’ve seen earlier: we bind to the name and we bind to the city and we’re kind of off and running.

Modify the above example with Filter

Page 17: SPA AngularJS Draft

Modules, Routes and Factories

Page 18: SPA AngularJS Draft

The first thing to talk about is although I created the controller in some previous demo’s right in the view that’s not the recommended way to do it.Keep in mind you might actually have different views. You might have a mobile view, maybe one specific to iPad or Surface or something like that, and maybe have one for desktops. It’s very possible.

Just means “Heh! What’s the name of the module you’ve defined in JavaScript?”Creating a Module:

What exactly is the empty array for? This is where dependency injection comes in because your module might actually rely on other modules to get data.

We say “Heh Angular! Create me a module called demoApp.” I need to rely on another module. In this case I just called it helperModule. This would be some other JavaScript file that you might reference.telling Angular “Go find that module. Go look it up wherever it is and inject it in and make it available to my controllers and directives and filters and factories and all that stuff that this particular module might have.

Creating a Controller in Module<html ng-app="demoApp"><div ng-controller="SimpleController">

<ul><li ng-repeat="cust in customers">{{cust.name + ' ' + cust.city}}</li>

</ul> </div><script>

var demoApp = angular.module('demoApp', []);var controllers = {};controllers.SimpleController=function($scope) {

$scope.customers = [{name: 'Dave Jones', city: 'Phoenix'}, {name:'Jamie Riley', city:'New York'},{name: 'Heedy Wahlin', city: 'Atlanta'}, {name:'Thomas Winter', city: 'Seattle'}];

};demoApp.controller(controllers);

</script>

Page 19: SPA AngularJS Draft

The Role of Routes

at some point if you’re building a single page application you’re going to need routes because we need to load different views into our shell page.Defining Routes

Declarative markup• ng:include Include HTML partials like cfinclude.• ng:repeat Loop over collections like cfloop.• ng:show / ng:hide Show or hide nodes based on a condition.• ng:class Add or remove classes from nodes.• ng:click / ng:change Handle user interactions with the page.

• Expressions {{user.name}}• Filters {{user.dateRegistered | date: 'MM/yyyy'}}

Page 20: SPA AngularJS Draft

Two way data binding• Form controls <input name="echo"> {{echo}}• Automatic evaluation <button ng:click="value = value + 1"> {{value}}

Model-View-Controller<form ng:controller="ProfileController" ng:submit="save()"><h2>Hello, {{user.name}}.</h2><p>You can edit your profile details below.</p><label>Email <input name="user.email"></label><label>Address <textarea name="user.address"></textarea></label><input type="submit" value="Save"></form><script>function ProfileController() {this.user = {name: 'Elliott', email: '[email protected]'};this.save = function() {// Ajax request to save the user};};</script>

Dependency Injection• Automatic injectionfunction ProfileController($resource, activityService_) { ... };• Explicit injectionfunction ProfileController(resource, activityService) { ... };ProfileController.$inject = ['$resource', 'activityService'];

RESTful resources• Like ORM for REST• Supports caching, bulking and JSONP• Mocks provided for testing<script>// $resource is automatically injected by name.function ProfileController($resource) {var Users = $resource('/users/me');this.user = Users.get();this.save = function() {Users.save(this.user);};};</script>

Service abstraction

Page 21: SPA AngularJS Draft

• Define services for use in your controllers• Easily swapped out for testingangular.service('profileService', function($resource) {return $resource('profiles/:id');});function ProfileController(profileService_) {// ...});

Create your own custom tags widgets• Define your own widgets<app:ProfileEditor profile="user"></app:ProfileEditor>• Reusable Components<jqui:Button icon="ui-icon-gear">Click Me</jqui:Button>• Attributes<input name="tags" jqui:autocomplete="tagList">

Testability• No DOM manipulation in controllers• Mocks provided for XHR• Easily mock out services• Angular services are not special• JsTD and Jasmine integration

End-to-End Runner<script>describe('ProfileController', function() {it('should save profiles', function() {browser().navigateTo('/profiles/mine');expect(element('h2').text()).toEqual('Hello, Elliott.');input('firstname').enter('Ethan');element('#save').click();browser().reload();expect(element('h2').text()).toEqual('Hello, Ethan.');});});</script>

End-to-End DSL<script>describe('ProfileController', function() {it('should save profiles', function() {browser().navigateTo('/profiles/mine');

Page 22: SPA AngularJS Draft

expect(profilePage().greeting()).toEqual('Hello, Elliott.');profilePage().firstName().enter('Ethan');profilePage().save();browser().reload();expect(profilePage().greeting()).toEqual('Hello, Ethan.');});});</script>

Good example dealing with DOM. Here we will change style of an html tag by binding its style property to a model.

<!doctype html><html > <head> <script src="angular.min.js"></script> <style type="text/css"> .style1{ border:1px #333 solid; width:300px; } .style2{ border:1px #999999; background-color:#0099FF; color:#fff; width:300px; } </style> </head> <body> <div ng-app> <input type="text" ng-model="data.source" > <h2 class="{{data.source}}">Hello AngularJS</h2> </div> </body></html>

Modulesvar firstModule = angular.module("firstModule", []);

Now we will add controller to this module, notice what has been changed from the way

we defined the controller above.

var firstModule = angular.module("firstModule",[]);

Page 23: SPA AngularJS Draft

firstModule.controller("FruitController", function ($scope){                $scope.fruits=['Apple','Banana','Watermelon','Peach']; });

Still our app does not know about our module, to use our module we need to define to

our ng-app

<html ng-app="firstModule">

Simple AngularJS http://stephanebegaudeau.tumblr.com/

Expressions: In order to create the views of your application, AngularJS let you execute expressions directly within your HTML pages.<!DOCTYPE HTML><html ng-app> <head>

<script src="angular.min.js"></script> </head>

<body> <div>1+1 = {{1+1}}</div> </body></html>

Scope

The scope is used to link the controllers and the views to which they are binded. A

controller can add data and function in its scope and then they will be accessible in the

view. In our case, we have used in the view a variable named “users” which was created

in the scope by the controller “UsersCtrl”.

Partial ViewsAngularJS is very good to build single page web applications. For those who are not familiar with this concept, it consists on a web application where you only have one “real” HTML page whose content can be changed in Javascript without having to download a new page. The new content is created programmatically in Javascript of with the use of templates. Those applications have advantages like performances (since you are not downloading a new HTML page each time you are navigating to a new page) and drawbacks like history management (what happens if your users click on the button back of their browser?).With AngularJS, you see that you are using a framework created by people who know what they are doing, as a result most of the problems of regular single page web applications are handled by AngularJS itself.In order to build your application, You define a main page (index.html) which acts as a container for your web application. In this page, you can bind part of your application to a specific AngularJS module with the directive “ngApp”. You can bind the whole page to a single AngularJS module if you want. After that, you can use the directive “ngView" in order to use partial views.Your module will tell AngularJS which view should be display in the “ngView” element. This directive also let you separate the content of your application in dedicated files.

Page 24: SPA AngularJS Draft

Code Organization in Large AngularJS and JavaScript Applications

Modularity

Hopefully the trite metaphors haven't been too tedious but here's the recap:

Your significant other is the new developer on the team who's been asked to fix a bug on

one of the many screens in your app.

The developer sifts through the directory structure and sees all the controllers, models

and services neatly organized. Unfortunately it tells him/her nothing about which objects

are related or have dependencies on one another.

If at some point the developer wants to reuse some of the code, they need to collect files

from a bunch of different folders and will invariably forget code from another folder

somewhere else.

Believe it or not, you rarely have a need to reuse all of the controllers from the e-

commerce app in the new reporting app you're building. You may however have a need

to reuse some of the authentication logic. Wouldn't it be nice if that was all in one place?

Let's reorganize the app based on functional areas:

cart/

CartModel.js

Page 25: SPA AngularJS Draft

CartService.js

common/

directives.js

filters.js

product/

search/

o SearchResultsController.js

o SearchResultsModel.js

ProductDetailController.js

ProductModel.js

ProductService.js

user/

LoginController.js

RegistrationController.js

UserModel.js

UserService.js

Any random developer can now open the top-level folder and immediately gain insight

into what the application does. Objects in the same folder have a relationship and

some will have dependencies on others. Understanding how the login and registration

process work is as easy as browsing the files in that folder. Primitive reuse via copy/paste

can at least be accomplished by copying the folder into another project.

With AngularJS we can take this a step further and create a module of this related code:

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

 

userModule.factory('userService', ['$http', function($http) {

return new UserService($http);

}]);

 

userModule.factory('userModel', ['userService', function(userService) {

return new UserModel(userService);

}]);

 

Page 26: SPA AngularJS Draft

userModule.controller('loginController', ['$scope', 'userModel',

LoginController]);

 

userModule.controller('registrationController', ['$scope', 'userModel',

RegistrationController]);

http://viralpatel.net/blogs/angularjs-introduction-hello-world-tutorial/

<!DOCTYPE html><html ng-app><head>    <title>Hello World, AngularJS - ViralPatel.net</title>    <script type="text/javascript"        src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script> </head><body>         Write some text in textbox:    <input type="text" ng-model="sometext" />     <h1>Hello {{ sometext }}</h1>     </body></html>

ng-appFirst thing that we notice is an attribute ng-app within <html> tag. This attribute tells the Angular

to be active in this portion of the page. So in our case entire document. If you want to enable

Angular only at specific location in your webpage then you can define ng-app attribute to any

DIV or other tag.

ng-model and Two way data bindingWe define attribute ng-model in textbox as ng-model=”sometext”. ng-model binds the state of

textbox with model value. In our case we define a model sometext. This model value is bound

with the value of textbox using ng-model attribute. Thus when the textbox value changes,

Angular automatically changes the model sometext with this value. This is called Two way data

binding. Similarly, if we change the model value than Angular will change the value of textbox.

Two way data binding is the core of Angular’s magical spell. It just works. You’ll get to know

about it more once we start adding complexity in our application.

AngularJS two-way data binding is its most notable feature and reduces the amount of code

written by relieving the server backend from templating responsibilities.

Page 27: SPA AngularJS Draft

{{ sometext }}Note how we wrap our model value in double curly braces. This tell Angular to bind the value of

modelsometext in place of {{ sometext }}.

Thus any change in sometext model value changes the text inside <h1> tag.

ng-show / ng-hideNow lets further modify our demo and add one more Angular attribute ng-show. In below code,

we added attribute ng-show=”sometext” to <h1> tag.<!DOCTYPE html><html ng-app><head>    <title>Hello World, AngularJS - ViralPatel.net</title>    <script type="text/javascript"        src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script> </head><body>         Write some text in textbox:    <input type="text" ng-model="sometext" />     <h1 ng-show="sometext">Hello {{ sometext }}</h1>     </body></html>

Filter uppercase and lowercaseAs its name suggest, this filter convert the expression into uppercase letters. Lets check a quick

demo. Lets modify few lines from our above example and use uppercase filter.<!DOCTYPE html>

<html ng-app>

<head>

    <title>Hello World, AngularJS - ViralPatel.net</title>

    <script type="text/javascript"

        src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>

 

</head>

<body>

     

    Write some text in textbox:

Page 28: SPA AngularJS Draft

    <input type="text" ng-model="sometext" />

 

    <h1>Hello {{ sometext }}</h1>

    <h4>Uppercase: {{ sometext | uppercase }}</h4>

    <h4>Lowercase: {{ sometext | lowercase }}</h4>

     

</body>

</html>

1. What are Scopes?

Before we get into Controllers let us understand Scopes. Scope is nothing but an object that

Glues the View with Controller. They hold the Model data that we need to pass to view. Scope

uses Angular’s two-way data binding to bind model data to view.

Imaging $scope as an object that links Controller to the View. It is controllers responsibility to

initialize the data that the view needs to display. This is done by making changes to $scope.

Let us see a small Hello World application to understand $scope.<!DOCTYPE html>

<html ng-app>

<head>

<title>Hello World, AngularJS - ViralPatel.net</title>

<script type="text/javascript"

    src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>

</head>

<body>

<div ng-controller="ContactController">

     Email:<input type="text" ng-model="newcontact"/>

    <button ng-click="add()">Add</button>

    <h2>Contacts</h2>

Page 29: SPA AngularJS Draft

    <ul>

        <li ng-repeat="contact in contacts"> {{ contact }} </li>

    </ul>

</div>

<script type="text/javascript">

    function ContactController($scope) {

        $scope.contacts = ["[email protected]", "[email protected]"];

        $scope.add = function() {

        $scope.contacts.push($scope.newcontact);

        $scope.newcontact = "";

        }

    }

</script>

</body>

</html>

1.2. ng-controller

This attribute defines a Controller to be bound with the view. In this case we defined a controller

called ContactController in DIV using ng-controller attribute. Thus whatever we put inside that

DIV, the ContactController will have its influence on it.

ContactController is nothing but a plain vanilla JavaScript function. In the demo we defined it as

function. Also see the definition of ContactController function. There is an object $scope which

we pass as an argument. This object is used to bind the controller with view. When AngularJS

initialize this controller, it automatically creates and injects the $scope object to this function

using dependency injection (More on dependency injection in coming tutorials). For now just note

that the $scope object is created by Angular and injected in this controller function.

Page 30: SPA AngularJS Draft

2. Initial state of a scope object

Typically, when you create an application you need to set up an initial state for an Angular scope.

In our case we need initial state to be list of contacts.

On $scope object, we defined an array called contacts:$scope.contacts = ["[email protected]", "[email protected]"]

When Angular initilize this function (ContactController), it automatically creates this array and

binds it in$scope object. Then in our view we display the array using ng-repeat attribyte.

Thus, $scope provides us with a way to pass/retrieve objects from Controller to View and vice-

versa.

2.1. ng-clickIt is also possible to define functions on $scope and use the same in View. In our demo, we

created a function add() on $scope and use it on Add button click:$scope.add = function() {

    ...

}

The function add() is bound to Add button using an attribute ng-click. ng-click binds the click

event on the button or link or any clickable element with the function that is defined within

$scope. So in this case, whenever Add button is clicked, the add() method on $scope will be

called.

In add() method we add (or push) a string in contacts array. This is the string that user types in

textbox. Note that we bind textbox using ng-model attribute.<input type="text" ng-model="contact" ...

This textbox’s value we got in $scope.contact as we bind it using ng-model attribute.

Pretty nice, isn’t it!!

3. How to define a Controller

So we got some basic idea of what Controllers are. Just plain vanilla JavaScript functions that we

add in an Angular application to add some business logic and bind the view with model.

In the above demo, we defined controller as JavaScript function. While this is the easiest way to

define them, but is certainly not advisable one. If your application grows, soon you’ll have bunch

of controllers lying here and there in code poluting the JavaScript namespace.

Page 31: SPA AngularJS Draft

So instead of defining controller as:function ContactController($scope) {

    //...

}

3.1. AngularJS Modules

So what-the-heck are modules? Well, modules are the logical entities that you divide you app in.

So your app can contain several modules (like Transaction, Report, etc.). Each module represent

a logical entity within the app.

Furthermore, each modules have several Controllers. As referred in above diagram, a module

can contain one or more controllers and views. We haven’t touch based on Views. We will see

how each module can be linked with view using Routing in AngularJS in our next tutorial. For

now just assume that each controller has one or more views linked to it.

So in this case, we can add one or more controllers to a module. Let us check the syntax to

create a module and add controller to it:var myApp = angular.module('myApp',[]);

 

Page 32: SPA AngularJS Draft

myApp.controller('ContactController', ['$scope', function($scope) {

    $scope.contacts = ["[email protected]", "[email protected]"];

    $scope.add = function() {

        $scope.contacts.push($scope.contact);

        $scope.contact = "";

    }

}]);

In above example we created a module called myApp using angular.module() method. Then

we added a controller ContactController to this module. This is just an alternate way of defining a

controller but recommended one.

Notice how controller is declared using myApp.controller() method. We passed an array to

this method. First argument of array is string ‘$scope’ and next is the function itself that

representContactController. We explicitly told Angular that we have one argument

(dependency) to our ContactController which is $scope. This is useful when you Minify or

obfuscate JavaScript for production release. In that case the argument $scope might be renamed

to $s, but because we defined string ‘$scope’ as first argument, Angular is aware that first

dependency to this controller is $scope object.

To cut it short, always stick to the above way of defining controllers.

4. Nested ControllersWe can declare the scope of controller in our HTML page using ng-controller attribute. For

example:<div ng-controller="CarController">

    ...

</div>

We can declare number of controllers and nest them within each other. For example:<div ng-controller="CarController">

    My name is {{ name }} and I am a {{ type }}

    

    <div ng-controller="BMWController">

        My name is {{ name }} and I am a {{ type }}

Page 33: SPA AngularJS Draft

        <div ng-controller="BMWMotorcycleController">

            My name is {{ name }} and I am a {{ type }}

        </div>

    </div>

</div>

<script>

function CarController($scope) {

    $scope.name = 'Car';

    $scope.type = 'Car';

}

function BMWController($scope) {

    $scope.name = 'BMW';

}

function BMWMotorcycleController($scope) {

    $scope.name = 'BMWMotorade';

    $scope.type = 'Motorcycle';

}

Page 34: SPA AngularJS Draft

</script>

4.1. Online Demo

Play on JSFiddle – http://jsfiddle.net/viralpatel/gWz4K/

In above demo, notice how each nested Controller’s scope override the scope of parents

controller. First we defined a controller CarController which defines two

variables name and type within scope. NextBMWController is nested within CarController

using ng-controller attribute. BMWController overridesname attribute and change it to BMW. It

does not change type attribute so type attribute is still Car.

BMWMotorcycleController is the inner-most controller defined within controllers hierarchy. It

overrides both name and type attribute of scope.

This way you can nest one controller within another and take advantage of parent controllers

attributes whenever needed.

5. Inheritance in ControllersIn order to take advantage of inheritance of scope in Nested controllers, one has to define

Controllers one into another using ng-controller attribute. Sometimes you don’t want to define

controllers like this but still want to use power of inheritance within controllers. May be you want

to put common logic into BaseController and use it in all the child controllers.

In order to achieve this, we must use $injector object that AngularJS provides.<div ng-controller="BMWController">

    

    My name is {{ name }} and I am a {{ type }}

    <button ng-click="clickme()">Click Me</button>

</div>

    

<script>

Page 35: SPA AngularJS Draft

function CarController($scope) {

 

    $scope.name = 'Car';

    $scope.type = 'Car';

 

    $scope.clickme = function() {

        alert('This is parent controller "CarController" calling');

    }

}

 

function BMWController($scope, $injector) {

    

    $injector.invoke(CarController, this, {$scope: $scope});

    

    $scope.name = 'BMW';

 

}

</script>

5.1. Online Demo

Play on JSFiddle – http://jsfiddle.net/viralpatel/WCZcZ/

We define two controllers, CarController an BMWController. CarController defines two attributes

name and type on $scope and also defines one method clickme().

BMWController just override name attribute. Notice that it does not have name and clickme

defined within its body. These attributes are defined by parent controller in this case

CarController. Within BMWController, we initialize CarController and bind it into current scope

using $injector.invoke() method.

Once this is done, notice how in HTML page the BMWController points to its parent’s attributes.

Page 36: SPA AngularJS Draft

6. End to end application using AngularJS Controller

Let us apply the knowledge that we acquired so far and create a ContactManager application.

Following are some basic requirements of this application:1. User can add new contact (name, email address and phone number)2. List of contacts should be shown3. User can delete any contact from contact list4. User can edit any contact from contact list

Following is the HTML code which defines a FORM to save new contact and edit contact. And

also it defines a table where contacts can be viewed.

6.1. The HTML<div ng-controller="ContactController">

    <form>

    <label>Name</label>

        <input type="text" name="name" ng-model="newcontact.name"/>

    <label>Email</label>

        <input type="text" name="email" ng-model="newcontact.email"/>

    <label>Phone</label>

        <input type="text" name="phone" ng-model="newcontact.phone"/>

        <br/>

        <input type="hidden" ng-model="newcontact.id" />

     <input type="button" value="Save" ng-click="saveContact()" />

    </form>

<table>

<thead>

<tr>

    <th>Name</th>

    <th>Email</th>

    <th>Phone</th>

    <th>Action</th>

</tr>

Page 37: SPA AngularJS Draft

</thead>

<tbody>

<tr ng-repeat="contact in contacts">

    <td>{{ contact.name }}</td>

    <td>{{ contact.email }}</td>

    <td>{{ contact.phone }}</td>

    <td>

        <a href="#" ng-click="edit(contact.id)">edit</a> |

        <a href="#" ng-click="delete(contact.id)">delete</a>

    </td>

 </tr>

</tbody>

</table>   

</div>

Just note that we have used ng-model, ng-click and ng-repeat attributes from Angular so far.

To add life to this application, we add following JavaScript code.

6.2. The JavaScriptvar uid = 1;

function ContactController($scope) {

    

    $scope.contacts = [

        { id:0, 'name': 'Viral',

          'email':'[email protected]',

          'phone': '123-2343-44'

        }

    ];

    

Page 38: SPA AngularJS Draft

    $scope.saveContact = function() {

        

        if($scope.newcontact.id == null) {

        //if this is new contact, add it in contacts array

        $scope.newcontact.id = uid++;

        $scope.contacts.push($scope.newcontact);

        } else {

        //for existing contact, find this contact using id

        //and update it.

        for(i in $scope.contacts) {

            if($scope.contacts[i].id == $scope.newcontact.id) {

            $scope.contacts[i] = $scope.newcontact;

            }

        }               

        }

        

        //clear the add contact form

        $scope.newcontact = {};

    }

    

    $scope.delete = function(id) {

        

        //search contact with given id and delete it

        for(i in $scope.contacts) {

            if($scope.contacts[i].id == id) {

                $scope.contacts.splice(i,1);

                $scope.newcontact = {};

            }

Page 39: SPA AngularJS Draft

        }

        

    }

    

    

    $scope.edit = function(id) {

    //search contact with given id and update it

        for(i in $scope.contacts) {

            if($scope.contacts[i].id == id) {

                //we use angular.copy() method to create

                //copy of originial object

                $scope.newcontact = angular.copy($scope.contacts[i]);

            }

        }

    }

}

First thing to note, we created a variable uid and set its initial value to 1. This variable is used to

generate unique ids for each new contact we save. In real life application you may want to do this

at backend.

We defined one controller ContactController. This controller defines following objects within

$scope:

Scope object Type Comment

$scope.contacts ArrayArray to store contact objects. In real life app, this should be maintained at server side.

$scope.saveContact

JavaScript Function

Saves the newcontact object within contacts array. Check if contact is new or is being updated

$scope.deleteJavaScript Function

Delete the contact object from contacts list based on id specified

$scope.edit JavaScript Update the contact object in contacts list based on id specified

Page 40: SPA AngularJS Draft

Function

6.3. Online Demo

Play on JSFiddle – http://jsfiddle.net/viralpatel/JFYLH/

You can add new contact using the above form. Once new contact is saved, the list showing

contacts will be updated. Each contact can be edited and deleted. You got the gist 

Building a simple single page application using AngularJSI am going to walk you through building a SPA (single page application) usingAngularJS,

Google's latest JavaScript MVC framework. After developing applications

using Backbone.js, Spine.js and good ol' jQuery I fell in love with AngularJS. It makes

development of SPAs actually fun removing a lot of the boilerplate that most of the other

frameworks make you write to get a simple app started.

The app we are going to build today is a simple multipage website that will read data in

from a static JSON file. We will be covering setting up AngularJS, routing, rendering

partials, communication between controllers and loading JSON asynchronously.

Download the source code View the demo

Page 41: SPA AngularJS Draft

Sections

Setting up AngularJS

Routing

Rendering partials

Loading JSON

Communicating between controllers

Before we get started it's a good idea to watch the intro videos on angularjs.org as they

cover most of the basics. I'm going to assume that you understand the concepts of how

the controller binds $scope with the views and how the ng-modeldirective works.

Setting up AngularJS

This tutorial will require you to run these files via a web server. If you have

apache/MAMP/WAMP set up you should be able to create a new directory under your

webroot and access via localhost. I like to run the npm module nws which creates a web

server in the current directory allowing me to get started quickly.

Html

The first thing you will want to do is setup your module. You do this by adding theng-

app attribute to your html tag. In the case of our application we will call our module Site.

<html lang="en-US" ng-app="Site">

The next thing we want to do is set up a controller. The controller is bound to the

element you add it to and it's children. We are going to add an AppController to our body

tag which allows the entire body to inherit from this controller. To add a controller you

use the ng-controller attribute.

<body ng-controller="AppController">

Here is a template including AngularJS from CDNJS that I will be using throughout this

tutorial.

JavaScript

Now that our html is set up we need to create the module and controller in

our/js/site.js file that is included.

Page 42: SPA AngularJS Draft

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

function AppController ($scope) {

}

The first line creates our Site module and the function defines our AppController. The

controller receives one argument (at the moment) $scope which binds models between

the view (html) and controller.

Routing

If you took a look at the template above you will have noticed that there are three links in

the nav bar: Home, About and Contact. We want to be able to route to these links and

load a section from the JSON file based on the slug.

The first thing we need to do is configure our Site module to use the $routeProviderand

then set up our routes.

Site.config(function ($routeProvider) {

$routeProvider

.when('/page/:slug', {templateUrl: 'partials/page.html', controller: 'RouteController'})

.otherwise({redirectTo: '/page/home'});

});

We are passing in an anonymous function to the modules config method. In the function

we are passing in Angular's $routeProvider service which allows us to define routes. The

two methods we are using are when() which takes a path and hash of options including

the templatePath and controller and otherwise() which allows us to redirect to a route if one

is not found.

We are defining one route for this application /page/:slug. This path contains

the:slug parameter, we can use this later using the $routeParams service to extract the

page data from the JSON.

We are also setting a controller for this route (RouteController). This controller is in

charge of binding the page content to the view.

function RouteController ($scope, $routeParams) {

// Getting the slug from $routeParams

var slug = $routeParams.slug;

Page 43: SPA AngularJS Draft

// We need to get the page data from the JSON

// $scope.page = ?;

}

Now when you try and visit the page you should be redirected to /#/home and if you try

and type in anything else it will redirect you back.

Rendering Partials

When we defined our route we set a templateUrl. This points to a static html file that

contains 2 simple expressions containing properties that will be bound to the

RouteController's $scope.

<!-- partials/page.html -->

<h1>{{page.title}}</h1>

{{page.content}}

To include this partial into your layout you need to use the <ng-view></ng-view>directive.

This will automatically be replaced with the partial set in the routes. You can see that this

is included already in the template provided above.

Loading JSON

Let's load some data into this application. I've created a simple static JSON data store

(in real life this would probably be generated by an API) which we will load in via Ajax

when the application starts.

// pages.json

{

"home": {

"title": "Home",

"content": "This is the home page. Welcome"

},

"about": {

"title": "About",

"content": "This is the about page. Welcome"

},

"contact": {

"title": "Contact",

Page 44: SPA AngularJS Draft

"content": "This is the contact page. Welcome"

}

}

We should only load the JSON file once, cache it to a variable and access the variable

when we need the data. Let's use Angular's $http service to grab the JSON file. To use

the $http service we will need to pass it as an argument to theAppController.

function AppController ($scope, $rootScope, $http) {

// Load pages on startup

$http.get('/pages.json').success(function (data) {

$rootScope.pages = data;

});

}

We are also passing in $rootScope which all scopes inherit from. We do this so this so

that we can access the pages JSON data in our RouteController. We can then access

the page data by using the slug we captured earlier and bind it to the scope so it's

accessible in our partial.

function RouteController ($scope, $rootScope, $routeParams) {

// Getting the slug from $routeParams

var slug = $routeParams.slug;

$scope.page = $rootScope.pages[slug];

}

Communicating between controllers

We've already demonstrated one way to communicate between controllers using

the $rootScope. Another option is using events. In Angular you can emit events and listen

to events in different controllers while passing data from the emitter to the listener.

We want to pass the slug from the RouteController to the AppController so that we can

set the active class on the current menu link. Angular has a ng-class directive which

allows you to add conditional classes to elements.

<li ng-class="{active: slug == 'home'}"><a href="/#/page/home">Home</a></li>

<li ng-class="{active: slug == 'about'}"><a href="/#/page/about">About</a></li>

Page 45: SPA AngularJS Draft

<li ng-class="{active: slug == 'contact'}"><a href="/#/page/contact">Contact</a></li>

You can see that the RouteController is emitting the slug and the AppController is listening

for the slug which then sets it onto it's scope and exposes it to the view.

function AppController ($scope, $rootScope, $http) {

// Load pages on startup

$http.get('/pages.json').success(function (data) {

$rootScope.pages = data;

});

// Set the slug for menu active class

$scope.$on('routeLoaded', function (event, args) {

$scope.slug = args.slug;

});

}

function RouteController ($scope, $rootScope, $routeParams) {

// Getting the slug from $routeParams

var slug = $routeParams.slug;

$scope.$emit('routeLoaded', {slug: slug});

$scope.page = $rootScope.pages[slug];

}

I hope you guys enjoyed this walkthrough. I will be writing more about AngularJS in the

future. If you guys have any questions about this post or have any topics you are

interested in let me know in the comments.

Angular JS Concepts Overview

1. <!doctype html>

2. <html ng-app>

3. <head>

4. <script src="http://code.angularjs.org/1.0.6/angular.min.js"></script>

5. </head>

6. <body>

7. <p ng-init=" name='World' ">Hello {{name}}!</p>

8. </body>

9. </html>

Page 46: SPA AngularJS Draft

1. The browser loads the HTML and parses it into a DOM2. The browser loads angular.js script3. Angular waits for DOMContentLoaded event4. Angular looks for ng-app directive, which designates the application boundary5. The Module specified in ng-app (if any) is used to configure the $injector6. The $injector is used to create the $compileservice as well as $rootScope7. The $compile service is used to compile the DOM and link it with $rootScope8. The ng-init directive assigns World to thename property on the scope9. The {{name}} interpolates the expression toHello World!

ScopeThe scope is responsible for detecting changes to the model section and provides the execution context for expressions. The scopes are nested in a hierarchical structure which closely follow the DOM structure. (See individual directive documentation to see which directives cause a creation of new scopes.)

The following example demonstrates how the name expression will evaluate into a different value

depending on which scope it is evaluated in. The example is followed by a diagram depicting the scope boundaries.

1. <!doctype html>

2. <html ng-app>

3. <head>

4. <script src="http://code.angularjs.org/1.0.6/angular.min.js"></script>

5. <script src="script.js"></script>

6. </head>

7. <body>

8. <div ng-controller="GreetCtrl">

9. Hello {{name}}!

10. </div>

11. <div ng-controller="ListCtrl">

12. <ol>

Page 47: SPA AngularJS Draft

13. <li ng-repeat="name in names">{{name}}</li>

14. </ol>

15. </div>

16. </body>

17. </html>

How to get started (Part 1 of the AngularJS - from beginner to expert in 7 steps series)This is the first post of AngularJS - from beginner to expert in 7 steps series.

AngularJS redefines how to build front-end applications. Instead of being afraid to cross the boundary between HTML and JavaScript, it takes it head-on.

Application frameworks, like Backbone, EmberJS, and others, require developers to extend from JavaScript objects that are specific to their frameworks. Although this approach has its merits, it unnecessarily pollutes your object space and requires you to have intimate knowledge of abstract objects that exist in memory. But we accept it because the web wasn’t originally designed to be as interactive as we expect it to be today, and we need frameworks to help us close the gap between JavaScript and HTML.

AngularJS closes that gap.

Instead of manipulating the DOM “directly,” you annotate your DOM with metadata (directives), and Angular manipulates the DOM for you.

AngularJS also does not depend on (or exclude the use of) any other framework. You can even build AngularJS apps in non-AngularJS frameworks.

It just works.

Sound awesome? It is. In this 7-part series we’re going to walk you through how to get started writing serious apps with AngularJS - even if you’ve never touched it before.

Follow along on this journey, and we’ll teach you how to become an expert AngularJS developer.

Page 48: SPA AngularJS Draft

First things first: When should you use AngularJS?AngularJS is an MV* framework that is ideal for use when building client-side single-page apps. It is not a library, but aframework for building dynamic web pages. It focuses on extending HTML and providing dynamic data binding, and it plays well with other frameworks (e.g., jQuery).

If you are building a single-page app, AngularJS will be perfect for you. Gmail, Google Docs, Twitter, and Facebook all fit into the AngularJS sweet spot. Game development and other apps that heavily manipulate the DOM or need pure speed are not good fits for AngularJS.

Now that we’ve gotten through that intro, here is the first topic you need to understand in order to learn AngularJS:

1. How to start writing an appThroughout this tutorial series, we are going to be building an NPR audio player that will show us the current stories on the show Morning Edition and play them in our browser. To see the fully finished demo, head over here.

When writing an AngularJS app, we write the behavior and interaction together alongside the presentation.

Writing this way can be confusing at first, especially if you have experience with other frameworks where the two are generally separate. Once you get the hang of it, it’ll become second nature.

Let’s look at the simplest app you can build with AngularJS:

<!doctype html>

<html ng-app>

<head>

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>

</head>

<body>

<div>

Page 49: SPA AngularJS Draft

<input type="text" ng-model="yourName" placeholder="Enter a name here">

<h1>Hello, {{ yourName }}!</h1>

</div>

</body>

</html>

Try it

Hello, !As you can see, you get bi-directional data binding without any work.

Bi-directional data binding means that if you change data on the back end, your changes will show up in your view automagically (actually, there’s no magic involved; we’ll get into how this works soon).

Similarly, if you change data in your view (e.g., by typing into a text box), it will automatically update your model.

So what did we do in our app?

ng-app ng-model=“yourName” {{ yourName }}

First, we used our most important (and most easily forgotten) term: the ng-app attribute on the <html> tag. Without this tag, the AngularJS process does not start.

Second, we told AngularJS that we want to set up bi-directional data binding on the yourName model on the page.

Third, we told AngularJS to display the data yourName in the directive template called {{ yourName }}.

That’s it. We’ve created a dynamic app that would ordinarily have taken much longer and many more lines of code to build: We did not have to specify any rules on bi-directional data binding, we didn’t have to write any updating code, we didn’t have to specify any models, and, in fact, we haven’t even touched JavaScript yet. We won’t have to do that until we want to build apps with more customized behavior.

Page 50: SPA AngularJS Draft

As you’ll see, all of the above just works because of the power of AngularJS’s design.

Building your appIn this section we’ll discuss an app we’ll call myApp. You can follow along with our series by git cloning the repository (instructions below) or by following along with our instructions. Create an index.html file with the following content:

<!doctype html>

<html ng-app="myApp">

<head>

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>

<script src="js/main.js"></script>

</head>

<body>

</body>

</html>

Then, make a directory called js and make a file in that directory called main.js, like so:

mkdir js

touch js/main.js

This HTML page will load both AngularJS and our app that we’ll write in main.js. Almost all of the work that we will do in this section will be in the main.js file.

In order to extend and customize our app, we’ll need to write some JavaScript. All the JavaScript that we will write will go into our main.js file.

angular.moduleTo define an AngularJS app, we first need to define an angular.module. An Angular module is simply a collection of functions that are run when the

Page 51: SPA AngularJS Draft

application is “booted.” (We’re not going to discuss configuration and run blocks in this series, but we’ll address them in future sections.)

Next, we need to define the module in our main.js file:

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

This line creates the Angular module named myApp. (Don’t worry about the second argument – the empty array, [] – for now. We’ll get to it.)

Now, we want to instantiate our myApp module on our page and tell Angular where in the DOM tree our app lives. To instantiate the module in a page, we’ll be using the ng-app directive, which tells Angular that we want our module to own that part of the DOM tree.

We can instantiate our own app (module) by simply passing the name of our app as the value in our index.html file:

<html ng-app="myApp">

When we refresh the page, Angular will bootstrap myApp.

We can set ng-app on any element in the DOM, and that’s where Angular will launch on the page. This step is how we can write an Angular app inside of any web page, even if the rest of the application isn’t written in Angular.

<h2>I am not inside an AngularJS app</h2>

<div ng-app="embeddedApp">

<h3>Inside an AngularJS app</h3>

</div>

For an app that will take over the entire page, you can place the ng-app directive on the html element.

Once we’ve defined our app, we can start building out the rest of the application. We’ll build using $scope, which is one of the most important Angular concepts. We will cover the $scope service in depth in Part 2 of our 7-part series.

So there we have it - the basic structure for an Angular app. We’ll use this as a starting point to build our NPR player.

Update: Read the next section of the series here.

Page 52: SPA AngularJS Draft

The official repository for the beginner series is available as a git repo here: https://github.com/auser/ng-newsletter-beginner-series.

To get this repo locally, ensure you have git installed, clone the repo, and check out the part1 branch:

git clone https://github.com/auser/ng-newsletter-beginner-series.git

git checkout -b part1

Want to know when Part 2 and every article in this series is released? Sign up for ng-newsletter below.

This is the second post of AngularJS - from beginner to expert in 7 steps.

We started our first post by showing you how to start out building an AngularJS app. In this post, we’ll discuss a fundamental concept in understanding how AngularJS works and how you can use it to your advantage.

Throughout this tutorial series, we are going to be building an NPR audio player that will show us the current stories on the show Morning Edition and play them in our browser. To see the fully finished demo, head over here.

Part 2. ScopesA $scope is an object that ties a view (a DOM element) to the controller. In the Model-View-Controller structure, this $scopeobject becomes the model. It provides an execution context that is bound to the DOM element (and its children).

Although it sounds complex, the $scope is just a JavaScript object. Both the controller and the view have access to the $scopeso it can be used for communication between the two. This $scope object will house both the data and the functions that we’ll want to run in the view, as we’ll see.

All AngularJS apps have a $rootScope. The $rootScope is the top-most scope that is created on the DOM element that contains the ng-app directive.

This is where AngularJS binds data and functions when explicit $scopes are not set in the page. This is why the example inpart 1 works.

In this example, we’re working with the $rootScope. We add an attribute on the scope of name in our main.js file. By putting this function in the app.run function, we’ll guarantee that it will run prior to the rest of the

Page 53: SPA AngularJS Draft

app. You can think of the runfunction being the main method of the angular app.

app.run(function($rootScope) {

$rootScope.name = "Ari Lerner";

});

Now, anywhere in our view, we can reference this attribute using the expression/template: {{ }}, like so:

{{ name }}

We’ll go more in-depth into how the expression template syntax works later in this series.

See it:Ari Lerner

In summary:

Anything that we attach to this $scope object will become available to the view. Likewise, any changes that the controller makes to the model will show up as

changes in the view.To really see the power of scopes, let’s attach a controller to a DOM element, which will create a $scope for the element and allow us to interact with it.

ng-controllerTo explicitly create a $scope object, we’ll attach a controller object to a DOM element using the ng-controller directive on an object, like so:

<div ng-controller="MyController">

{{ person.name }}

</div>

The ng-controller directive creates a new $scope object for the DOM element and nests it in the containing $scope. In this example, the parent $scope of the div with ng-controller is the $rootScope object. The scope chain looks like this:

Page 54: SPA AngularJS Draft

Now, MyController sets up a $scope that we can access from inside the DOM element. In this case, we’re going to create a person object on the $scope of MyController, in main.js:

app.controller('MyController', function($scope) {

$scope.person = {

name: "Ari Lerner"

};

});

Now we can access this person object in any child element of the div where ng-controller='MyController' is written because it is on the $scope.

See it

Ari Lerner

With one exception, all scopes are created with prototypal inheritance, meaning that they have access to their parent scopes. By default, for any property that AngularJS cannot find on a local scope, AngularJS will crawl up to the containing (parent) scope and look for the property or method there. If AngularJS can’t find the property there, it will walk to that scope’s parent and so on and so forth until it reaches the $rootScope.

The one exception: Some directives can optionally create an isolate scope and do not inherit from their parents.

For instance, say we have a ParentController that contains the user object and a ChildController that wants to reference that object:

app.controller('ParentController', function($scope) {

Page 55: SPA AngularJS Draft

$scope.person = {greeted: false};

});

app.controller('ChildController', function($scope) {

$scope.sayHello = function() {

$scope.person.greeted = true;

}

});

When we bind the ChildController under the ParentController in our view, we can reference the property on the parent scope just as if it were on the ChildController:

<div ng-controller="ParentController">

<div ng-controller="ChildController">

<input type="text" ng-model="person.name" placeholder="Name"></input>

<a ng-click="sayHello()">Say hello</a>

</div>

{{ person }}

</div>

Page 56: SPA AngularJS Draft

See it

Say hello Reset

{"greeted":false}

Integrating in myAppNow let’s use the power of the $scope to manage our NPR app. We left off last article having just defined the app module. Now, let’s start breaking up our DOM structure and build our fundamental functionality.

Just like we saw in the example above, we’ll create a root controller called PlayerController. Our PlayerController will be responsible for keeping track of our audio element and will handle fetching our listing of NPR programs.

Let’s create both of our controllers, back in main.js:

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

app.controller('PlayerController', ['$scope', function($scope) {

}]);

app.controller('RelatedController', ['$scope', function($scope) {

}]);

AudioThese controllers don’t do much yet, so let’s get some audio going on in the app. In this tutorial, we’ll be using the HTML5audio element, so make sure you have an HTML5-compliant browser (we prefer Google Chrome).

To add an audio element, we can either add it in the HTML or in our controller. Since we’ll be interacting with the audio element primarily in our controller, it makes most sense to create it here.

In our PlayerController, let’s create an audio element. We’ll store it on our scope, which, as you know by now, means that we’ll connect the view to the controller through the $scope object.

app.controller('PlayerController', ['$scope', function($scope) {

Page 57: SPA AngularJS Draft

$scope.audio = document.createElement('audio');

}]);

Now, this setup is kind of boring, as it doesn’t do very much yet. We’ll cover ‘fetching’ the data in the next part of our series, so for now we’ll hardcode a .mp4 url.

In the same PlayerController, set the src of the audio file to an .mp4 URL to which you have access. For the purpose of convenience, we’re using an NPR audio file that we are hosting, but we can point to any URL. Simply set your audio source as the URL of the audio file.

app.controller('PlayerController', ['$scope', function($scope) {

$scope.playing = false;

$scope.audio = document.createElement('audio');

$scope.audio.src = '/media/npr.mp4';

}]);

Try itPlay Playing audio: false

The audio won’t play unless we tell it to play. To do that, we can simply call $scope.audio.play(), and the HTML5 audio element will take over and start playing from the mp4 stream.

We can provide an interactive element to the user by creating a button that binds to an action on the $scope. We’ll discuss this more in-depth in the next section, however the HTML for the view above looks like:

<div ng-controller="PlayerController">

<button ng-click="play()" class="button" ng-show="!playing">Play</button>

<button ng-click="stop()" class="button alert" ng-show="playing">Stop</button>

Playing audio: <b>{{ playing }}</b>

</div>

Notice that we don’t have to reference the audio element we create on the scope. This is because we are creating it in the controller when the

Page 58: SPA AngularJS Draft

controller is loaded using document.createElement("audio"). Note that we are going to refactor this component later in the tutorial series. It’s generally a bad idea to manipulate DOM components inside of a controller (thanks Brad Green for pointing this out as a note). We’re keeping this component here to maintain simplicity.

We’ve added a few variables in the view that we are keeping track of in on the $scope. We’re using a few advanced concepts that we’ll discuss in detail throughout the series, so do not worry if it doesn’t all make sense immediately:

app.controller('PlayerController', ['$scope', function($scope) {

$scope.playing = false;

$scope.audio = document.createElement('audio');

$scope.audio.src = '/media/npr.mp4';

$scope.play = function() {

$scope.audio.play();

$scope.playing = true;

};

$scope.stop = function() {

$scope.audio.pause();

$scope.playing = false;

};

$scope.audio.addEventListener('ended', function() {

$scope.$apply($scope.stop());

});

}]);

That’s a solid introduction into AngularJS’s $scope service. In the next section, we’ll cover bi-directional data binding in AngularJS.

Update: Check out part3 of our series.

The official repository for the beginner series is available as a git repo here: https://github.com/auser/ng-newsletter-beginner-series.

Page 59: SPA AngularJS Draft

To get this repo locally, ensure that you have git installed, clone the repo, and check out the part2 branch:

git clone https://github.com/auser/ng-newsletter-beginner-series.git

git checkout -b part2

Want to know when Part 3 and every article in this series is released? Sign up for ng-newsletter below.

This is the third post of AngularJS - from beginner to expert in 7 steps.

We started our first post by showing you how to start out building an AngularJS app. In the second post, we discussed how scopes and the $scope service work.

Throughout this tutorial series, we are building an NPR audio player that will show us the current stories on the showMorning Edition and play them in our browser. To see the fully finished demo, head over here.

3. Data bindingWe can make our app a bit more interesting by binding an input field to the person.name attribute. This step sets up a bi-directional binding from the input field to the page.

Bi-directional in this context means that if the view changes the value, the model sees the change, and if the model changes the value, then the view will see the change. AngularJS sets this up automatically for you. We’ll discuss thedigest_loop in depth in an upcoming article, if you’re curious how it works.

Page 60: SPA AngularJS Draft

To set up this binding, we’ll use the ng-model function on the input, like so:

<div ng-controller="MyController">

<input type="text" ng-model="person.name" placeholder="Enter your name" />

<h5>Hello {{ person.name }}</h5>

</div>

Now that we have a binding set up (yes, it’s that easy), we can see how the view changes the model:

Try it

Hello

As you type in the input box, you’ll see that the name underneath changes automatically. That change illustrates how our data binding works in one direction, from the view to the model.

We can also change the model on the (client-side) back end and see it reflected on the front end.

To illustrate our data binding from back end to front end, let’s make a clock function in our MyController model that will update a value on the $scope. In this example, we’ll create a clock that will tick every second (as clocks usually do) and change the data on the clock variable:

app.controller('MyController', function($scope) {

$scope.person = { name: "Ari Lerner" };

var updateClock = function() {

$scope.clock = new Date();

};

var timer = setInterval(function() {

$scope.$apply(updateClock);

}, 1000);

updateClock();

});

Page 61: SPA AngularJS Draft

As you can see, as we change the clock variable on the model, the view automatically updates to reflect our changes.

We can show the clock variable that’s attached on the $scope in the view simply by surrounding it in {{ }}:

<div ng-controller="MyController">

<h5>{{ clock }}</h5>

</div>

See it it

"2013-08-10T11:23:13.597Z"

InteractionNotice that we have bound data to the input field above. We don’t have to limit this data binding to only data. We can also call functions on the $scope (as mentioned previously).

To bind buttons or links (or any DOM element, really), we’ll use another built-in directive, ng-click. The ng-click directive binds the click event to the method (the mousedown browser event) to the DOM element (i.e., when the browser fires a click event on the DOM element, the method is called). Similar to our previous example, the binding looks like:

<div ng-controller="DemoController">

<h4>The simplest adding machine ever</h4>

<button ng-click="add(1)" class="button">Add</button>

<a ng-click="subtract(1)" class="button alert">Subtract</a>

<h4>Current count: {{ count }}</h4>

</div>

Both the button and the link will be bound to an action on the containing $scope, so when they are pressed (clicked), Angular will call the method. Note that when we are telling Angular what method to call, we’re putting it in a string with the parentheses.

Now, let’s create an action on our DemoController.

app.controller('DemoController', function($scope) {

Page 62: SPA AngularJS Draft

$scope.counter = 0;

$scope.add = function(amount) { $scope.counter += amount; };

$scope.subtract = function(amount) { $scope.counter -= amount; };

});

See it

The simplest adding machine ever

Add Subtract

Current count: 1

Data binding and AJAX in our appInteractionAs we saw in the last example of the previous section, we bound a button to the view using the data binding we just learned about. In that example, we bound the button to the play() action and bound the PlayerController’s method play on the play button (and the same for the stop button, with the stop method).

AJAXIn the last tutorial, we referenced a locally hosted audio file; however, doing so gives us a static NPR file instead of a live NPR feed. In our NPR app, we’ll use $http to populate the list of available news clips we can play.

Out of the box, AngularJS supports AJAX (or asynchronous JavaScript and XML). This support gives us the ability to make requests back and forth from a server or multiple servers, which is essential to a client-side app like ours that needs to get and set data.

AngularJS supports AJAX through a service (which we’ll discuss in an upcoming section) called the $http service.

All of the core AngularJS services are prefixed with $. We’ve seen this before with the $scope service.

The $http service is incredibly flexible and gives us many different ways to call AJAX services. To keep this tutorial simple, we’re only going to

Page 63: SPA AngularJS Draft

focus on the simplest method possible. We’ll dive deeper into the $http service in a more advanced section in the future.

Before we go too far into detail, let’s make a request with the $http service:

$http({

method: 'JSONP',

url: 'http://api.openbeerdatabase.com/v1/beers.json?callback=JSON_CALLBACK'

}).success(function(data, status, headers, config) {

// data contains the response

// status is the HTTP status

// headers is the header getter function

// config is the object that was used to create the HTTP request

}).error(function(data, status, headers, config) {

});

Try it

Make request

Request result: []

The $http service is a core AngularJS service that helps faciliate communication with remote HTTP servers via the XMLHttpRequest object or through JSONP.

Note that AngularJS will take care of handling a JSONP request if you append the EXACT string: callback=JSON_CALLBACKas just above. AngularJS will replace JSON_CALLBACK with the proper callback it constructs for you.

The $http service is a function that takes a configuration object, which defines how the HTTP request is constructed. It will return a promise that has two methods success and error.

To get a list of the available audio clips, let’s make a request to NPR’s API. First, you’ll need to register with NPR to get an API key. Head over to their site at http://www.npr.org/templates/reg/ or click here to register from this page.

Page 64: SPA AngularJS Draft

Keep note of your API key. We’ll use that in a minute. Now, we’re going to set up our PlayerController to call the $http service to fetch a list of the clips.

Just like we did above, let’s call the $http service to make a request, this time to get all the clips. We want this service to run when the controller is instantiated, so we can simply put this method right in the controller function (which is run when the controller is created), like so:

var apiKey = 'YOUR_KEY',

nprUrl = 'http://api.npr.org/query?id=61&fields=relatedLink,title,byline,text,audio,image,pullQuote,all&output=JSON';

app.controller('PlayerController', function($scope, $http) {

// Hidden our previous section's content

// construct our http request

$http({

method: 'JSONP',

url: nprUrl + '&apiKey=' + apiKey + '&callback=JSON_CALLBACK'

}).success(function(data, status) {

// Now we have a list of the stories (data.list.story)

// in the data object that the NPR API

// returns in JSON that looks like:

// data: { "list": {

// "title": ...

// "story": [

// { "id": ...

// "title": ...

}).error(function(data, status) {

// Some error occurred

});

Page 65: SPA AngularJS Draft

});

Now that we have the the list of clips in data in the success function, we can bind it to the $scope object simply by storing the list on $scope in the success callback:

// from above

}).success(function(data, status) {

// Store the list of stories on the scope

// from the NPR API response object (described above)

$scope.programs = data.list.story;

}).error(function(data, status) {

// Some error occurred

Now, just like above, we can reference this data in our view simply by referencing programs in our view. Note that one of the benefits of using AngularJS is that it will automatically populate promises into your view when the promise resolves.

<div ng-controller="PlayerController">

{{ programs }}

</div>

Try it

In the next section, we’ll discuss how to display this data object in our view in a meaningful way using some built-in directives (and a little bit more).

The official repository for the beginner series is available as a git repo here: https://github.com/auser/ng-newsletter-beginner-series.

To get this repo locally, ensure that you have git installed, clone the repo, and check out the part3 branch:

git clone https://github.com/auser/ng-newsletter-beginner-series.git

Page 66: SPA AngularJS Draft

git checkout -b part3

Want to know when Part 4 and every article in this series is released? Sign up for ng-newsletter below.

Form validation with AngularJSClient-side form validations are one of the coolest features inside of AngularJS. AngularJS form validation enables you to write a modern HTML5 form that is interactive and responsive from the start.

There are many form validation directives available in AngularJS. We’ll talk about a few of the most popular ones here and then we’ll get into how to build your own validations.

<form name="form">

<label name="email">Your email</label>

<input type="email" name="email" ng-model="email" placeholder="Email Address" />

</form>

AngularJS makes it pretty easy for us to handle client-side form validations without adding a lot of extra effort. Although we can’t depend on client-side validations keeping our web application secure, they provide instant feedback of the state of the form.

To use form validations, we first must ensure that the form has a name associated with it, like in the above example. Got it? Great!

All input fields can validate against some basic validations, like minimum length, maximum length, etc. These are all available on the new HTML5 attributes of a form.

It is usually a great idea to use the novalidate flag on the form element. This will prevent the browser from submitting the form.

Let’s look at all the validation options we have that we can place on an input field:

RequiredTo validate that a form input has been filled out, simply add the html5 tag: required to the input field:

<input type="text" required />

Page 67: SPA AngularJS Draft

Minimum lengthTo validate that a form input input is at least a {number} of characters, add the AngularJS directive ng-minlength="{number}"to the input field:

<input type="text" ng-minlength=5 />

Maximum lengthTo validate that a form input is equal to or less than a number of characters, add the AngularJS directiveng-maxlength="{number}":

<input type="text" ng-maxlength=20 />

Matches a patternTo ensure that an input matches a regex pattern, use the AngularJS directive: ng-pattern="/PATTERN/":

<input type="text" ng-pattern="/a-zA-Z/" />

EmailTo validate an email address in an input field, simply set the input type to email, like so:

<input type="email" name="email" ng-model="user.email" />

NumberTo validate an input field has a number, set the input type to number:

<input type="number" name="email" ng-model="user.age" />

UrlTo validate that an input represents a url, set the input type to url:

<input type="url" name="homepage" ng-model="user.facebook_url" />

Custom validationsAngularJS makes it very easy to add your own validations as well by using directives. For instance, let’s say that we want to validate that our

Page 68: SPA AngularJS Draft

username is available in the database. To do this, we’ll implement a directive that fires an ajax request whenever the form changes:

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

app.directive('ensureUnique', ['$http', function($http) {

return {

require: 'ngModel',

link: function(scope, ele, attrs, c) {

scope.$watch(attrs.ngModel, function() {

$http({

method: 'POST',

url: '/api/check/' + attrs.ensureUnique,

data: {'field': attrs.ensureUnique}

}).success(function(data, status, headers, cfg) {

c.$setValidity('unique', data.isUnique);

}).error(function(data, status, headers, cfg) {

c.$setValidity('unique', false);

});

});

}

}

}]);

Control variables in formsAngularJS makes properties available on the containing $scope object available to us as a result of setting a form inside the DOM. These enable us to react to the form in realtime (just like everything else in AngularJS). The properties that are available to us are:

Note that these properties are made available to us in the format:

Page 69: SPA AngularJS Draft

formName.inputFieldName.property

Unmodified formA boolean property that tells us if the user has modified the form. This is true if the user hasn’t touched the form, and falseif they have:

formName.inputFieldName.$pristine;

Modified formA boolean property if and only if the user has actually modified the form. This is set regardless of validations on the form:

formName.inputFieldName.$dirty

Valid formA boolean property that tells us that the form is valid or not. If the form is currently valid, then this will be true:

formName.inputFieldName.$valid

Invalid formA boolean property that tells us that the form is invalid. If the form is currently invalid, then this will be true:

formName.inputFieldName.$invalid

The last two properties are particularly useful for showing or hiding DOM elements. They are also very useful when setting a class on a particular form.

ErrorsAnother useful property that AngularJS makes available to us is the $error object. This object contains all of the validations on a particular form and if they are valid or invalid. To get access to this property, use the following syntax:

formName.inputfieldName.$error

If a validation fails then this property will be true, while if it is false, then the value has passed the input field.

Page 70: SPA AngularJS Draft

A little style never hurtsWhen AngularJS is handling a form, it adds specific classes to the form based upon their state. These classes are named similar to the properties that we can check as well.

These classes are:

.ng-pristine {}

.ng-dirty {}

.ng-valid {}

.ng-invalid {}

The correspond to their counterpart on the particular input field.

When a field is invalid, the .ng-invalid class will be applied to the field. This particular site sets the css class as:

input.ng-invalid { border: 1px solid red; } input.ng-valid { border: 1px solid green; }

Putting it all togetherLet’s build a signup form. This signup form will include the person’s name, their email, and a desired username.

Let’s start by looking at what the form will look like when it’s done. Go ahead, play with it, start typing in the input fields, see how the form responds and reacts. Notice that the submit button becomes disabled when the form goes invalid:

Signup form

Your name

Your email

Username

Submit

Let’s start with defining the form:

Page 71: SPA AngularJS Draft

<form name="signup_form" novalidate ng-submit="signupForm()">

<fieldset>

<legend>Signup</legend>

<button type="submit" class="button radius">Submit</button>

</fieldset>

</form>

This form’s name is signup_form and we are going to call signupForm() when the form is submitted.

Now, let’s add the name of the user:

<div class="row">

<div class="large-12 columns">

<label>Your name</label>

<input type="text"

placeholder="Name"

name="name"

ng-model="signup.name"

ng-minlength=3

ng-maxlength=20 required />

</div>

</div>

Try it

Your name

Breaking this down. First thing to note is that I use Foundation for my css layouts, so you’ll see that syntax is my forms. We added a form that has an input called name that is bound (by ng-model) to the object signup.name on the $scope object.

Page 72: SPA AngularJS Draft

We also setup a few validations. These validations say we have to have a minlength of our name of 3 or more characters. We also impose a maximum limit of characters of 20 characters (this will be invalid at 21 characters and higher). Lastly, werequire that the name be filled out for the form to be valid.

Let’s use the properties to show and/or hide a list of errors if the form is invalid. We’ll also use the $dirty attribute to make sure the errors don’t show up if the user hasn’t touched the field:

<div class="row">

<div class="large-12 columns">

<label>Your name</label>

<input type="text"

placeholder="Name"

name="name"

ng-model="signup.name"

ng-minlength=3

ng-maxlength=20 required />

<div class="error"

ng-show="signup_form.name.$dirty && signup_form.name.$invalid">

<small class="error"

ng-show="signup_form.name.$error.required">

Your name is required.

</small>

<small class="error"

ng-show="signup_form.name.$error.minlength">

Your name is required to be at least 3 characters

</small>

<small class="error"

ng-show="signup_form.name.$error.maxlength">

Page 73: SPA AngularJS Draft

Your name cannot be longer than 20 characters

</small>

</div>

</div>

</div>

Try it

Your name

Breaking this down, we’re only going to show our errors if the form is invalid and changed, just as before. This time, we’ll look through each of the valiations and only show a particular DOM element if the particular validation property is invalid.

Let’s look at the next set of validations, the email validation:

<div class="row">

<div class="large-12 columns">

<label>Your email</label>

<input type="email"

placeholder="Email"

name="email"

ng-model="signup.email"

ng-minlength=3 ng-maxlength=20 required />

<div class="error"

ng-show="signup_form.email.$dirty && signup_form.email.$invalid">

<small class="error"

ng-show="signup_form.email.$error.required">

Your email is required.

</small>

Page 74: SPA AngularJS Draft

<small class="error"

ng-show="signup_form.email.$error.minlength">

Your email is required to be at least 3 characters

</small>

<small class="error"

ng-show="signup_form.email.$error.email">

That is not a valid email. Please input a valid email.

</small>

<small class="error"

ng-show="signup_form.email.$error.maxlength">

Your email cannot be longer than 20 characters

</small>

</div>

</div>

Try itYour email

This time (with the entire form included), we’re looking at the email field. Note that we set the type of the input field to emailand added a validation error on $error.email. This is based off the AngularJS email validation (and the HTML5 attribute).

Finally, let’s look at our last input field, the username:

<div class="large-12 columns">

<label>Username</label>

<input type="text"

placeholder="Desired username"

name="username"

Page 75: SPA AngularJS Draft

ng-model="signup.username"

ng-minlength=3

ng-maxlength=20

ensure-unique="username" required />

<div class="error" ng-show="signup_form.username.$dirty &&

signup_form.username.$invalid">

<small class="error" ng-show="signup_form.username.

$error.required">Please input a username</small>

<small class="error" ng-show="signup_form.username.

$error.minlength">Your username is required to be at least 3

characters</small>

<small class="error" ng-show="signup_form.username.

$error.maxlength">Your username cannot be longer than 20

characters</small>

<small class="error" ng-show="signup_form.username.

$error.unique">That username is taken, please try another</small>

</div>

</div>

Try it

Username

In our last field, we’re using all the same previous validations, with the exception that we’ve added our custom validation. This custom validation is defined using an AngularJS directive:

app.directive('ensureUnique', ['$http', function($http) {

return {

require: 'ngModel',

Page 76: SPA AngularJS Draft

link: function(scope, ele, attrs, c) {

scope.$watch(attrs.ngModel, function() {

$http({

method: 'POST',

url: '/api/check/' + attrs.ensureUnique,

data: {'field': attrs.ensureUnique}

}).success(function(data, status, headers, cfg) {

c.$setValidity('unique', data.isUnique);

}).error(function(data, status, headers, cfg) {

c.$setValidity('unique', false);

});

});

}

}

}]);

When the form input is valid, this will make a POST request check to the server at /api/check/username to check if the username is available. Now, obviously since we’re only talking about front-end code here, we don’t have a backend to test this on, although it could easily be written.

Update: As per a discussion in the comments, I’ve added an update using the $timeout service. To check out that full source, check it out here.

Lastly, putting our button together, we can use the angular directive ng-disabled to disable and reenable the button when the form is valid:

<button type="submit" ng-disabled="signup_form.$invalid"

class="button radius">Submit</button>

As we said above, the form itself will have a $invalid and valid attributes given to us for free.

Page 77: SPA AngularJS Draft

Update 2: Although live validation is great, it can be abrasive to the user when they see errors pop-up while they are typing, long before they have put in a valid value. You can be nicer to your users if you show the validations either only after they have submitted the form or after they have moved off of the input. Let’s look at both ways to do that.

Show validations after submitTo show validations only after the user has attempted to submit the form, you can capture a ‘submitted’ value on the scope and check for that scope to show the error.

For instance, let’s take a look at the first example and only show the errors when the form has been submitted. On theng-show directive on for the form input, we can add a check to see if the form has been submitted (which we will implement shortly):

<form name="signup_form" novalidate ng-submit="signupForm()">

<fieldset>

<legend>Signup</legend>

<div class="row">

<div class="large-12 columns">

<label>Your name</label>

<input type="text"

placeholder="Name"

name="name"

ng-model="signup.name"

ng-minlength=3

ng-maxlength=20 required />

<div class="error"

ng-show="signup_form.name.$dirty && signup_form.name.

$invalid && signup_form.submitted">

Page 78: SPA AngularJS Draft

<small class="error"

ng-show="signup_form.name.$error.required">

Your name is required.

</small>

<small class="error"

ng-show="signup_form.name.$error.minlength">

Your name is required to be at least 3 characters

</small>

<small class="error"

ng-show="signup_form.name.$error.maxlength">

Your name cannot be longer than 20 characters

</small>

</div>

</div>

</div>

<button type="submit" class="button radius">Submit</button>

</fieldset>

</form>

Now, the error div will only show up if the signup_form.submitted variable has been set to true. We can implement this in thesignupForm action, like so:

app.controller('signupController', ['$scope', function($scope) {

$scope.submitted = false;

$scope.signupForm = function() {

Page 79: SPA AngularJS Draft

if ($scope.signup_form.$valid) {

// Submit as normal

} else {

$scope.signup_form.submitted = true;

}

}

}]);

Now, when your users try to submit the form while there is an invalid element, you can catch it and show them the appropriate errors.

Show validations only after blurIf you want to retain the real-time nature of the error input, you can show your users the errors after they have blurred off of the input form. To do this, we like to add a small directive that will attach a new variable to the form.

The directive we like to use is the ngFocus directive and it looks like:

app.directive('ngFocus', [function() {

var FOCUS_CLASS = "ng-focused";

return {

restrict: 'A',

require: 'ngModel',

link: function(scope, element, attrs, ctrl) {

ctrl.$focused = false;

element.bind('focus', function(evt) {

element.addClass(FOCUS_CLASS);

scope.$apply(function() {ctrl.$focused = true;});

Page 80: SPA AngularJS Draft

}).bind('blur', function(evt) {

element.removeClass(FOCUS_CLASS);

scope.$apply(function() {ctrl.$focused = false;});

});

}

}

}]);

To implement the ngFocus directive, we can simply attach this directive to the input element, like so:

<input ng-class="{error: signup_form.name.$dirty &&

signup_form.name.$invalid}" type="text" placeholder="Name"

name="name" ng-model="signup.name" ng-minlength=3 ng-maxlength=20

required ng-focus />

The ngFocus directive simply attaches an action to the blur and focus events on the form input and adds a class (ng-focused) and sets the form input field $focused as true. Then you can show your individual error messages depending if the form is focused or not. For instance:

<div class="error" ng-show="signup_form.name.$dirty &&

signup_form.name.$invalid && !signup_form.name.$focused">

I hope this post shows you how cool AngularJS form validation can be. Stay tuned for the next post and sign-up for the newsletter for weekly, up-to-date posts about the latest and greatest, curated angularjs news.

Build custom directives with AngularJSMost everything we use in AngularJS is a directive. Directives are what makes AngularJS so powerful and responsive. Directives are the root of AngularJS and how we as developers interact with AngularJS.

Although AngularJS is packed with powerful directives out of the box, often times we want to create our own reusable functionality. In this post, we’ll focus on how to tackle the seemingly complex process of creating

Page 81: SPA AngularJS Draft

directives. We’ll start with building simple directives and explain the process throughout the post.

To start making your own directive, let’s first understand what directives actually are. Directives, in AngularJS are, at their core functions that get run when the DOM is compiled by the compiler.

Using this powerful concept, AngularJS enables us to create new directives that we can encapsulate and simplify DOM manipulation. We can create directives that modify or even create totally new behavior in HTML.

If you’ve ever used any part of AngularJS before, you’ve used a directive, whether you know it or not. The ng-app attribute is a directive, so is ng-controller and all of the ng- prefixed attributes.

<body ng-app>

<input type="text" ng-model="name" placeholder="name">

<h1>{{ name }}</h1>

</body>

Try it

Type ‘Hello Ari Lerner’

When AngularJS loads this simple example, it will traverse the DOM elements looking for any directives that are associated with each DOM element. Once it’s found all of them (if there are multiple directives), it will then start running the directive and associating it with the DOM element. This all happens behind the scenes and automatically for you.

To invoke a directive from HTML, we simply can apply the directive in the DOM. That is to say, we pick one of the four methods for invoking a directive:

As an attribute:

<span my-directive></span>

As a class:

<span class="my-directive: expression;"></span>

Page 82: SPA AngularJS Draft

As an element:

<my-directive></my-directive>

As a comment:

<!-- directive: my-directive expression -->

These are the same in the eyes of AngularJS. In fact, AngularJS even gives you other options for invoking directives with name prefixes. These are all equivalent, as well:

<input type="text" ng-model="directivename" placeholder="name" />

<span ng-bind="directivename"></span>

<span ng:bind="directivename"></span>

<span ng_bind="directivename"></span>

<span x-ng-bind="directivename"></span>

<span data-ng-bind="directivename"></span>

Try itng-bind=“directivename”: 

ng:bind=“directivename”: 

ng_bind=“directivename”: 

x-ng-bind=“directivename”: 

data-ng-bind=“directivename”:

The last two are are the only methods of invoking directives that are HTML5 compliant and that will pass HTML5 validators.

Building our first directiveAlthough we’ll discuss in greater detail how directives actually work at the fundamental level later, let’s start by creating our first directive.

We’ll be walking through creating a sparkline directive that will show the weather forecast for the next few days based onopenweathermap data. We will be building this directive:

Page 83: SPA AngularJS Draft

Weather for San Francisco

020406080

Our first, basic directive looks like this:

app.directive('ngSparkline', function() {

return {

restrict: 'A',

template: '<div class="sparkline"></div>'

}

});

And then we’ll invoke it in our html:

<div ng-sparkline></div>

Notice that when we invoke it, the name of the directive is not the same as when we define it (ngSparkline vs. ng-sparkline). This is because AngularJS will handle translating the camel cased name when we define it to the snake case when we invoke it.

Although our first example doesn’t do very much (yet), it already is showing some powerful features. Anywhere in our html, we can add the attribute ng-sparkline and have the template be appended to the DOM element.

There are two ways to build a directive. In our example, we’re using the method of returning a directive description object. AngularJS expects either one of these objects or a link function when we’re creating a directive. Building a directive with the link function is usually enough for relatively simple directives. For the most part, we’ll be creating directives using the description object.

Restrict optionIn our example’s description object, we’re setting two config components. First, we’re setting the restrict config option. The restrict option is used to specify how a directive can be invoked on the page.

As we saw before, there are four different ways to invoke a directive, so there are four valid options for restrict:

'A' - <span ng-sparkline></span>

Page 84: SPA AngularJS Draft

'E' - <ng-sparkline></ng-sparkline>

'C' - <span class="ng-sparkline"></span>

'M' - <!-- directive: ng-sparkline -->

The restrict option can specify multiple options, as well. If you want to support more than one as an element or an attribute, simply make sure all are specified in the restrict keyword:

restrict: 'EA'

TemplateSecondly, in our example we’re also setting a template. This template is an inline template where we are specifying the html that will be appended (or replaced, we’ll discuss this shortly). This is particularly useful when we want to share directives across apps and you only want to pass a single file around.

TemplateUrlIf you prefer to load a template over ajax, you can specify the templateUrl option, which will use ajax to pull the template.

templateUrl: 'templates/ng-sparkline-template.html'

With that, we can start adding functionality. Before we can jump straight into that, we need to look at how the directive is instantiated in the DOM.

How directives are born (compilation and instantiation)When the DOM is done loading and the AngularJS process starts booting up, the first process that happens is the HTML is parsed by the browser as a DOM tree. This tree is then parsed using AngularJS’s $compile() method. $compile runs through the DOM tree and looks for directive declarations for the different DOM elements. Once all directive declarations are found for each DOM element and sorted (by priority, which we’ll get into shortly), the directive’s compile function is run and is expected to return a link() function. The $compile() function will return a linking function that wraps all of the containing DOM element’s directives' linking functions.

Finally, the linking function is invoked with the containing scope that attaches all of the associated directives to that scope. This is where we’ll do most of the work when building directives, as this is where we can

Page 85: SPA AngularJS Draft

register listeners, set up watches, and add functionality. The result of this process is why the live data-binding exists between the scope and the DOM tree.

Why have a compile and link function?So why does AngularJS have two functions that run at the compile phase instead of just combining them into one? Boiled down, the answer is for performance. It’s slow to compile and interpolate against scopes every time a new directive of the same type is created. Because of this, all of the slow parts of the compilation process are front-loaded into the compile phase, while the linking happens when everything is associated and attached to the DOM.

In summaryWe’ll use the compile function to both manipulate the DOM before it’s rendered and return a link function (that will handle the linking for us). This also is the place to put any methods that need to be shared around with all of the instances of this directive.

We’ll use the link function to register all listeners on a specific DOM element (that’s cloned from the template) and set up our bindings to the page.

Back to ngSparklineOur sparkline graph will need to do a little more than show us a div on the page to actually be useful. To do that, we’ll have to bind a controller input on the directive. Basically, we’ll want the directive to be driven by the input of another directive. In most cases, we’ll want to bind our directive to the ng-model directive’s controller.

Require optionWe’ll enforce that we need this dependency by setting the require option:

app.directive('ngSparkline', function() {

return {

restrict: 'A',

require: '^ngModel',

template: '<div class="sparkline"><h4>Weather for {{ngModel}}</h4></div>'

Page 86: SPA AngularJS Draft

}

});

Now, if we invoke the directive on the page without the ng-model directive, our browser will complain and throw an error. To invoke our directive now, we simply have to add the ng-model directive:

<input type="text" ng-model="city" placeholder="Enter a city" />

<div ng-sparkline ng-model="city"></div>

Notice, in the require option, we prefixed the controller with a ^. AngularJS gives you two options in the require option about how to declare requirements with a prefixed character:

^ -- Look for the controller on parent elements, not just on the local scope

? -- Don't raise an error if the controller isn't found

Scope

Just like in every other part of AngularJS DOM control, directives can be given their own scopes. This is important to note, because without declaring an isolated scope from the rest of the DOM, our directive could muck with the local controller scope and cause unexpected behavior.

To get around this trouble, AngularJS gives you the ability to isolate the scope of the directive from the rest of the page using the scope option.

app.directive('ngSparkline', function() {

return {

restrict: 'A',

require: '^ngModel',

scope: {

ngModel: '='

},

template: '<div class="sparkline"><h4>Weather for {{ngModel}}</h4></div>'

}

});

Page 87: SPA AngularJS Draft

The scope option can take one of two different options. It can be set to true (it’s false by default).

scope: true,

When the scope directive is set to true, a new scope will be created for the directive.

While it’s useful to ensure that a new scope will be created for the directive, that scope will still participate in the normal controller-scope hierarchical relationship. We can isolate the directive’s scope outside of the parent relationship by creating an isolate scope.

An isolate scope does not prototypically inherit from the parent scope, but creates an entirely new one. Creating this isolatescope will ensure that your directive does not mess with the existing scope.

To create an isolate scope, simply pass an object back in the scope option:

scope: {}

This will create an empty scope. This is not particularly useful because your directive will have nothing available on its scope (other than the variables that you manually add).

To make local variables on your local scope available to the new directive’s scope, you’ll have to pass one of the following three aliases in the object:

Local scope property

Binding a local scope (string) to the value of the DOM attribute, use the @ symbol. Now the value of the outer scope will be available inside your directive’s scope:

@ (or @attr)

Bi-directional binding

A bi-directional binding can be set up between the local scope property and the parent property using the = symbol. If the parent model changes, just like in normal data-binding then the local property will reflect the change.

= (or =attr)

Parent execution binding

Page 88: SPA AngularJS Draft

To execute a function in the context of the parent scope, we can bind a function using the & symbol. This is to say that when setting the value, a function wrapper will be created and point to the parent function.

To call the parent method with an argument, you’ll need to pass an object with the key being the name of the argument and the value being the argument to pass:

& (or &attr)

For example, if we’re writing an email client and we are creating an email textbox such as:

<input type="text" ng-click="sendMail()" />

<!-- Invoke the directive -->

<div scope-example ng-model="to" on-send="sendMail(email)" from-name="[email protected]" />

We have a model, a function, and a string. To get access to these on your directive’s scope:

scope: {

ngModel: '=',

onSend: '&',

fromName: '@'

}

Try it

Send

ngModel: onSend (status): Not sent fromName: [email protected]

Show controller source

Going back to our sparkline directive, we’ll need to pass in a city with our directive from which we want to pull the weather from openweathermap. To do this, we’ll start out by setting it statically on the directive by passing it in as an attribute:

Page 89: SPA AngularJS Draft

<div ng-sparkline ng-model="San Francisco"></div>

Our directive now looks like this:

app.directive('ngSparkline', function() {

return {

restrict: 'A',

require: '^ngModel',

scope: {

ngCity: '@'

},

template: '<div class="sparkline"><h4>Weather for

{{ngModel}}</h4></div>'

}

});

If we want to be more explicit and descriptive about what model we are requiring, we can change the require: '^ngModel'above to be require: '^ngCity'. This comes in handy when you are communicating requirements on a team or you want to reuse the directive in another project. The implementation would change to the more explicit version:

<div ng-sparkline ng-city="San Francisco"></div>

If we want to support this method of setting ng-city instead of ngModel, we’ll have to add some supporting logic. As we said above, the require option will inject the controller of the require option.

For ngCity to work, we’ll have to create a custom directive with a controller defined. This is as simple as:

app.directive('ngCity', function() {

return {

controller: function($scope) {}

Page 90: SPA AngularJS Draft

}

});

Alternatively, you can continue to use ngModel.

Pulling weather dataNow that we have the city, we can use openweathermap to grab the latest weather data.

In order to do this, we’ll have to set up a function that will run when the directive is linked to the DOM. If we write this function in the compile method, then we’ll modify the DOM in place.

app.directive('ngSparkline', function() {

return {

restrict: 'A',

require: '^ngCity',

scope: {

ngCity: '@'

},

template: '<div class="sparkline"><h4>Weather for

{{ngCity}}</h4></div>',

link: function(scope, iElement, iAttrs) {

// get weather details

}

}

});

The link function will be run as soon as the directive is linked to the DOM. In order to call out to a separate service, however, we’ll have

Page 91: SPA AngularJS Draft

to inject the $http service. Because of this, we’ll need to define a controller to get access to the service.

Controller optionIn a directive, when we set the controller option we are creating a controller for the directive. This controller is instantiated before the pre-linking phase.

The pre-linking and post-linking phases are executed by the compiler. The pre-link function is executed before the child elements are linked, while the post-link function is executed after. It is only safe to do DOM transformations after the post-link function.

We are defining a controller function in our directive, so we don’t need to define either of these functions, but it is important to note that we cannot do DOM manipulations in our controller function.

What does a controller function look like? Just like any other controller. We’ll inject the $http service in our controller (using the bracket injection notation):

app.directive('ngSparkline', function() {

return {

restrict: 'A',

require: '^ngCity',

scope: {

ngCity: '@'

},

template: '<div class="sparkline"><h4>Weather for

{{ngCity}}</h4></div>',

controller: ['$scope', '$http', function($scope, $http) {

$scope.getTemp = function(city) {}

}],

link: function(scope, iElement, iAttrs, ctrl) {

Page 92: SPA AngularJS Draft

scope.getTemp(iAttrs.ngCity);

}

}

});

Note that in our link function, we have access to all of the attributes that were declared in the DOM element. This will become important in a minute when we go to customize the directive.

Now we can create the function getTemp to fetch from the openweathermap.

var url = "http://api.openweathermap.org/data/2.5/forecast/daily?

mode=json&units=imperial&cnt=7&callback=JSON_CALLBACK&q="

$scope.getTemp = function(city) {

$http({

method: 'JSONP',

url: url + city

}).success(function(data) {

var weather = [];

angular.forEach(data.list, function(value){

weather.push(value);

});

$scope.weather = weather;

});

}

Page 93: SPA AngularJS Draft

Now, inside of our link function, we’ll have a promise that will be fulfilled by the controller method. A promise, if you’re not familiar, is basically an object that will return the result of an action that is run asynchronously.

<div ng-sparkline ng-city="San Francisco"></div>

See itThis will print out a bunch of JSON

Weather for San Francisco

Weather:

[{"dt":1376078400,"temp":

{"day":57.81,"min":57.81,"max":57.81,"night":57.81,"eve":57.81,"morn":57.81},"pressure":

1021.65,"humidity":99,"weather":[{"id":804,"main":"Clouds","description":"overcast

clouds","icon":"04n"}],"speed":6.05,"deg":228,"clouds":92},{"dt":1376164800,"temp":

{"day":64.09,"min":56.35,"max":64.09,"night":56.35,"eve":59.36,"morn":57.25},"pressure":

1022.84,"humidity":87,"weather":[{"id":500,"main":"Rain","description":"light

rain","icon":"10d"}],"speed":5.77,"deg":241,"clouds":0,"rain":0.5},

{"dt":1376251200,"temp":

{"day":64.45,"min":55.22,"max":64.56,"night":55.22,"eve":60.71,"morn":56.25},"pressure":

1021.66,"humidity":87,"weather":[{"id":800,"main":"Clear","description":"sky is

clear","icon":"01d"}],"speed":5.31,"deg":231,"clouds":0}]

As you can see, the directive is rendered on screen initially without data, but as soon as the link method is run (linking the specific element to the DOM), the getTemp method will run and will eventually populate the weather property on the scope.

Now, let’s take this data and create a sparkline with it. To start, we’ll want to pick a property on the weather to work on.

Let’s start by creating a chart on the high temperatures. To start with, we’ll need to create a $watch on the weather object. Because we are fetching the weather data asynchronously, we cannot simply write the method expecting the data to be populated for us when the linking function runs. No matter, AngularJS makes this incredibly easy with the built-in function$watch.

The $watch function will register a callback to be executed whenever the result of the expression changes. Inside the $digestloop, every time AngularJS detects a change, it will call this function. This has the side effect that we cannot depend on state inside this function. To counter this, we’ll check for the value before we depend on it being in place.

Page 94: SPA AngularJS Draft

Here is our new $watch function:

scope.getTemp(iAttrs.ngCity);

scope.$watch('weather', function(newVal) {

if (newVal) {

}

});

Every time the weather property on our scope changes, our function will fire. We will use d3 to chart our sparkline.

Here’s what we have so far:

app.directive('ngSparkline', function() {

var url =

"http://api.openweathermap.org/data/2.5/forecast/daily?

mode=json&units=imperial&cnt=14&callback=JSON_CALLBACK&q=";

return {

restrict: 'A',

require: '^ngCity',

scope: {

ngCity: '@'

},

template: '<div class="sparkline"><h4>Weather for

{{ngCity}}</h4><div class="graph"></div></div>',

controller: ['$scope', '$http', function($scope, $http) {

$scope.getTemp = function(city) {

$http({

Page 95: SPA AngularJS Draft

method: 'JSONP',

url: url + city

}).success(function(data) {

var weather = [];

angular.forEach(data.list, function(value){

weather.push(value);

});

$scope.weather = weather;

});

}

}],

link: function(scope, iElement, iAttrs, ctrl) {

scope.getTemp(iAttrs.ngCity);

scope.$watch('weather', function(newVal) {

// the `$watch` function will fire even if the

// weather property is undefined, so we'll

// check for it

if (newVal) {

var highs = [],

width = 200,

height = 80;

angular.forEach(scope.weather, function(value){

Page 96: SPA AngularJS Draft

highs.push(value.temp.max);

});

// chart

}

});

}

}

});

See itWeather for San Francisco

020406080

Show d3 source

Now that we have our chart being drawn, let’s look at ways that we can customize the directive when we invoke it.

Inside of our watch function, we’re currently setting a static height and width. We can do better than that by allowing the invocation to determine the width and the height. Because we have access to the iAttrs (the instance of the attributes on the instance of the DOM element), we can simply look there first; otherwise we can set a default.

Change the width and the height to look like this:

var width = iAttrs.width || 200,

height = iAttrs.height || 80;

When we invoke the directive, this time we can add a width to set the width:

<div ng-sparkline width='400'></div>

Now our sparkline changes width to be 400 pixels, instead of the default 200.

Page 97: SPA AngularJS Draft

See itWeather for San Francisco

020406080

Inside of our directive as it stands today, we have a label that tells us “Weather for .” Although this is convenient for demo purposes, we might not always want that label to be static inside the directive. We can set it to include any html that we put inside of the DOM element that contains our directive.

Transclude optionAlthough the name sounds complex, transclusion refers to compiling the content of the element and making the source available to the directive. The transcluded function is pre-bound to the calling scope, so it has access to the current calling scope.

Looking at an example, let’s change the invocation to:

<div ng-sparkline ng-city="San Francisco" width='400'>

<h3>A custom view of the weather in San Francisco</h3>

</div>

To get this to show up in our template, we’ll need to use a special directive called ngTransclude. This is how the template knows where to place the custom HTML. Let’s modify the template in our directive to include the custom content:

template: '<div class="sparkline"><div ng-transclude></div><div class="graph"></div></div>'

Additionally, we’ll have to tell AngularJS that our directive will be using transclusion. To do that, we’ll have to set the transclude option either to:

true, which will take the content of the directive and place it in the template ‘element’, which will take the entire defined element including the lower priority

directives.Set the transclude option to true, as we only want the content of our directive to show up in our template:

transclude: true

Page 98: SPA AngularJS Draft

See itA custom view of the weather in San Francisco

020406080

Replace optionSometimes it is better to replace the entire DOM object, rather than append the new template to it. AngularJS makes this easy to accomplish by simply adding replace option in the directive description object. Set the replace option to true, like so:

replace: true

Priority optionDirectives on elements are compiled in a sorted order based on priority. Sometimes it matters what ordered directives are applied. By setting a higher priority, you can almost guarantee the order in which the directives are applied. To set a higher priority of one directive over another, simply add the priority option and set it to a numerical value higher than 0 (the default):

priority: 10

Terminal optionSometimes it’s useful to stop the execution of the compiler for including other directives. This is most useful when used in conjunction with setting the priority. terminal will stop the execution of any directives at a lower priority than this one.

terminal: true

Next stepsWe’ve covered how to build a directive from the very low-level to the top. Hopefully you’ve gained some confidence and knowledge about how to move forward in the future and provide and build your own custom directives.

app.directive('ngSparkline', function() {

Page 99: SPA AngularJS Draft

var url = "http://api.openweathermap.org/data/2.5/forecast/daily?mode=json&units=imperial&cnt=14&callback=JSON_CALLBACK&q=";

return {

restrict: 'A',

require: '^ngCity',

transclude: true,

scope: {

ngCity: '@'

},

template: '<div class="sparkline"><div ng-transclude></div><div class="graph"></div></div>',

controller: ['$scope', '$http', function($scope, $http) {

$scope.getTemp = function(city) {

$http({

method: 'JSONP',

url: url + city

}).success(function(data) {

var weather = [];

angular.forEach(data.list, function(value){

weather.push(value);

});

$scope.weather = weather;

});

}

}],

link: function(scope, iElement, iAttrs, ctrl) {

scope.getTemp(iAttrs.ngCity);

scope.$watch('weather', function(newVal) {

Page 100: SPA AngularJS Draft

// the `$watch` function will fire even if the

// weather property is undefined, so we'll

// check for it

if (newVal) {

var highs = [];

angular.forEach(scope.weather, function(value){

highs.push(value.temp.max);

});

chartGraph(iElement, highs, iAttrs);

}

});

}

}

});

var chartGraph = function(element, data, opts) {

var width = opts.width || 200,

height = opts.height || 80,

padding = opts.padding || 30;

// chart

var svg = d3.select(element[0])

.append('svg:svg')

.attr('width', width)

.attr('height', height)

Page 101: SPA AngularJS Draft

.attr('class', 'sparkline')

.append('g')

.attr('transform', 'translate('+padding+', '+padding+')');

svg.selectAll('*').remove();

var maxY = d3.max(data),

x = d3.scale.linear()

.domain([0, data.length])

.range([0, width]),

y = d3.scale.linear()

.domain([0, maxY])

.range([height, 0]),

yAxis = d3.svg.axis().scale(y)

.orient('left')

.ticks(5);

svg.append('g')

.attr('class', 'axis')

.call(yAxis);

var line = d3.svg.line()

.interpolate('linear')

.x(function(d,i){return x(i);})

.y(function(d,i){return y(d);}),

path = svg.append('svg:path')

.data([data])

Page 102: SPA AngularJS Draft

.attr('d', line)

.attr('fill', 'none')

.attr('stroke-width', '1');

}

app.directive('ngCity', function() {

return {

controller: function($scope) {}

}

});

Small ToDo List<!DOCTYPE HTML><html ng-app> <head>

<script src="angular.min.js"></script> </head>

<body> <form name="form" ng-controller="Foo"><h2>{{tasks.length}} Tasks</h2><p><input type="text" ng-model="newTask"/><button ng-click="addTask()">Add</button></p><ul><li ng-repeat="(index, task) in tasks">{{task}} <button ng-click="removeTask(index)">X</button></li></ul></form>

<script>function Foo($scope){$scope.tasks = [];$scope.addTask = function() {$scope.tasks.push($scope.newTask);$scope.newTask = null;};

Page 103: SPA AngularJS Draft

$scope.removeTask = function (index) {$scope.tasks.splice(index, 1);};}</script> </body></html>

Angular provides$http (AJAX)$resource (Even easier for REST backends)

Brief Introduction to Model-View-Controller in AngularJS

Previous ChapterNext Chapter

This chapter will be a work in progress for the next few days. 

So far we have learned how to a basic program using Expressions in AnguarJS. In this chapter we will see how can you read and store values associated with various HTML elements (like input box  <input/> , select item  <select> ) in a JavaScript object/variable/anything without worrying about reading/setting it from/on DOM. We will also see what Model-View-Controller or MVC is? and how does AngularJS framework forces(for betterment) MVC on programmers. The reason the title of the chapter points to MVC is that we will achieve our goal of creating a GUI and reading the values of HTML elements using code which is written using Angular's forced MVC.

View

What represents a view in a website or a web application? The answer is simple: HTML. HTML content is what users/visitors see on a website. A little beautification with CSS is needed though. In AngularJS world the definition of a view has not changed, it is still the HTML content. Let us imagine that we are building a GUI for stock market information website. For simplicity we will keep just 3 components in our GUI:

Page 104: SPA AngularJS Draft

1. Dropdown to select a company whose stock prices are to be checked and 2. a label to show the stock price.

   

  Stock price = 200$

Input box for users to register their email id for subscribing to stock market email digests.

Subscribe

That's it. That makes our view in AngularJS application. Trivial! isn't it?

Controller

The piece of code which will read the email id from input box when user clicks on subscribe or the piece of code which will show the stock price for a company when a company is selected from the dropdown is called a controller. A controller in AngularJS is a JavaScript function. The controller function is defined by application programmers/us and is automatically called by AngularJS whenever the HTML(view) is loaded in the DOM tree. Remember that it is not automatically called when HTML(view) is rendered but when HTML is parsed and loaded in DOM tree.

function stockController($scope){

//Don't worry about the parameter name '$cope'. $ is allowed as part of variable name

//Code to handle changes in view/code to change view here.

//Going ahead we will also write the code in JQuery and compare it with AngularJS

}

You must be wondering about what  $scope  is and why is it needed as a parameter to

the function which is defined by you as a programmer. Well  $scope  is a JavaScript object passed by AngularJS and it supposed to be used by the programmer as a binder between view and controller. We had discussed in the chapter 1.1 that AngularJS obviates the task of writing data binding code between UI and JavaScript and  $scope  helps in that. The next section explains the role  $scope  plays.

Model

Model represents the current state of the view. For changing the stock market price label dynamically, the controller changes the model. In AngularJS a model is a

Page 105: SPA AngularJS Draft

property of the  $scope  object. e.g.  $scope.stockPrice="200$" . Similarly we can

assign $scope.subscribeEmailId (which can be any name and not just subscribeEmailId)

as a model for email Id input box. The special thing about this approach is that if we

type email Id in input box, the  $scope.subscribeEmailId  variable is auto filled with the

value you typed and vice versa if you change variable value from code, the changes are reflected in the GUI.Let me remind you that you should not get confused by '$'. $ is used to differentiate Angular variable names. Good programming practice to help you distinguish your variable names from Angular's :).

Now the question that would have arose in your mind is how can just by changing the value of variable the view is changed. We will discuss the internals a bit later but for now lets see how to achieve it from code. Remember we talked about Angular directives and Angular Expressions in previous chapter. The model variable can be used in HTML(View) as a value of an Angular directive or in Angular expression.e.g. HTML  <p ng-controller="stockCtrl" > {{ 'Stock price = ' + stockPrice }} </p> 

and corresponding JS code to change it.

function stockCtrl($scope){

$scope.stockPrice = "200$";

//It will replace the stockPrice variable in HTML Angular expression with the string

"200$"

}

Example code for understanding Model-View-Controller in AngularJS

Here is the link to the source code. Below is the output of the program shown in an iframe. It may take bit extra time to load if your internet connection is slow. You can see output of the program by clicking on . Explanation of the code here.

Console output for the above program.

 

Page 106: SPA AngularJS Draft

Explanation of the code

Let us understand the code step by step. We had discussed about directives in Angular earlier. Lets get introduced to some new directives and the expression which we have used in our example.

ng-app : Role discussed here

ng-controller="myController"

We have above learned the concept of a controller and we have seen how a controller function looks like. But to link a controller function with the view one has to use the directive  ng-controller . This directive can be used on any DOM element as

an attribute. Like any non boolean attribute one has to specify a value for it as well. The value we specified was "myController" . It tells angular that the controller for the

DOM element has the name myController and children DOM elements will have the same controller for them unless explicitly a new controller is specified for them using  ng-controller . We have also learned that controller is a JavaScript function. So if

you check the JavaScript code you will find a function with the name myController there. Don't worry about the code written in that controller, we will discuss that as well. Now this controller is called when the DOM tree is created. To prove that we have added two  console.log()  statements in our code. The log statement inside the

controller gets printed first and the log statement inside the onload function(DOM rendered callback) gets printed second. You can check it right now by opening a debugger in your browser. If you don't have one you can see the image attached above for proof. Now let us see how this controller serves its purpose of changing DOM without making the programmer worry about exact DOM elements.

{{ selectedCompany + ' Stock price =' + stockPrice[selectedCompany] }}

We have learned that the controller function is passed a special parameter  $scope  by Angular. This serves the purpose of binding between controller

and view. Now in our controller code we have added a new property to the $scope parameter: $scope.selectedCompany = "VMWare"; . This initializes the value

of  selectedCompany . So in our expression in HTML Code, the

variable  selectedCompany  is replaced with "VMWare". Simple! the programmer didn't

had to bother about the location of the DOM element. Also we have initialized the  stockPrice  object in our controller with three key value pairs, each for Google,

Microsoft and VMWare. Since  selectedCompany  is initialized as

"VMWare",  stockPrice["VMWare"]  will give you its stock price, which is 500$. Hence

the  stockPrice[selectedCompany]  is replaced with 500$.

ng-model="selectedCompany"

Page 107: SPA AngularJS Draft

This is a very important directive and is a special one. on't get bewildered by new

directives, they are the powerhouses of Angular and one cannot escape them. One also needs to

learn the behaviour exhibited by various directives to use Angular. Coming back to ng-model , it

should be used on HTML elements where you can change the value of HTML element using GUI. e.g.  <input> box or  <select>  item. The value of this directive/attribute

points to a variable specified as property of $scope in controller. For e.g. our select item has this attribute with value  "selectedCompany" . Since we have

initialized $scope.selectedCompany = "VMWare";  the select item's value is auto changed

to "VMWare". The special thing about  ng-model is that not only changes made

through controller are available to GUI but also the changes made by GUI are auto reflected in  $scope.selectedCompany  in the controller. Also every GUI

component/expression referring to "selectedCompany" gets updated. e.g. our expression gets updated with changes in select item.

To give the proof that changes made in GUI are auto reflected in controller we have associated  ng-model  with an input box.

<input ng-model="emailId" type="text"/>

Any text typed in the input box is auto stored in  $scope.emailId . So when a user clicks

on subscribe button, the controller need not search for the input box in DOM and read its value. Its there with it in the variable  $scope.emailId . Controller code can just

use it directly.

That brings end to this special chapter. In the coming chapters we will learn more concepts of AngularJS

A RESTful Client with Angular.jsPosted on March 4, 2013 by ijason — 3 Comments ↓

In my last post, I showed you how how to create a RESTful API in PHP. In this

post, I’ll show you how to implement that API using Angular.js.

Angular.js is a JavaScript framework developed by Google, designed to make

your front-end development as easy as possible. Angular follows the MVC

(model-view-controller) pattern of software development and encourages

loose coupling between presentation, data, and logic components.

To utilize my PHP API, I’m going to use $http service in Angular.

The $http service is a core Angular service that facilitates communication with

the remote HTTP servers via browser’s XMLHttpRequest object or via JSONP.

The first thing I’ll do is build my controller which I’ll call AppsController.js.

Controller

AppsController.js

Page 108: SPA AngularJS Draft

function AppListCtrl($scope, $http, $templateCache) {    $scope.listApps = function() {        $http({method: 'GET', url: './api.php?action=get_app_list', cache: $templateCache}).            success(function(data, status, headers, config) {                $scope.apps = data;                  //set view model                $scope.view = './Partials/list.html'; //set to list view            }).            error(function(data, status, headers, config) {                $scope.apps = data || "Request failed";                $scope.status = status;                $scope.view = './Partials/list.html';            });  }                          $scope.showApp = function(id) {      $http({method: 'GET', url: './api.php?action=get_app&id=' + id, cache: $templateCache}).          success(function(data, status, headers, config) {              $scope.appDetail = data;               //set view model              $scope.view = './Partials/detail.html'; //set to detail view          }).          error(function(data, status, headers, config) {              $scope.appDetail = data || "Request failed";              $scope.status = status;              $scope.view = './Partials/detail.html';          });  }                  $scope.view = './Partials//list.html'; //set default view  $scope.listApps();}AppListCtrl.$inject = ['$scope', '$http', '$templateCache'];

The $http service uses the GET request to retrieve the JSON object from the

server, in this case api.php. The data returned is used to fill the view model

object. $scope.view sets the partial view to render. Lets take a look at the

partial views.

Partial Views

list.html

<ul><li ng-repeat="app in apps">        <a href="" ng-click="showApp(app.id)">{{app.name}}</a></li></ul>

The list partial view loops through the view model and displays the app

names. ng-repeat="app in apps" is similar to a For Each loop in .NET. The ng-

click event calls the showApp function in the controller. It accepts one

parameter, the id, and uses a GET request to retrieve the app data.

The appDetail view model for the detail partial view is populated and the partial

view is rendered.

Page 109: SPA AngularJS Draft

detail.html

<table> <tr>   <td>App Name: </td><td>{{appDetail.app_name}}</td> </tr> <tr>   <td>Price: </td><td>{{appDetail.app_price}}</td> </tr> <tr>   <td>Version: </td><td>{{appDetail.app_version}}</td> </tr></table><br /><a href="" ng-click="listApps()">Return to the app list</a>

The detail partial view displays the data stored in the appDetail view model.

Main View

index.html

<html ng-app><script src="./JS/angular.min.js"></script><script src="./JS/AppsController.js"></script><body ng-controller="AppListCtrl">        <ng-include src="view"></ng-include> </body></html>

In the main view, ng-include fetches, compiles and includes an external HTML

fragment. As you can see creating a REST client with Angular.js can be short

and simple. For a higher level of abstraction, I’d recommend you check out

the $resource service.

AngularJS Example Using a Java RESTful Web ServiceJUL 13TH, 2013

AngularJS is the current MVV-Whatever JavaScript framework by

Google. Among other things, it provides bidirectional data

binding.

Although I’m neither a Java nor a JavaScript expert, I choose the

following scenario for my ‘Hello-World’ example:

Page 110: SPA AngularJS Draft

1. Java backend provides a RESTful web service.

2. AngularJS consumes the web service.

That’s it.

Project structureI intentionally put the backend and frontend code in the same

project to simplify the example. In a real project you probably

want to have seperate projects for front- and backend.

1

2

3

4

5

6

7

8

+---------------------------------------------------+

| demo project |

| |

| +----------------+ +---------------+ |

| | backend (Java) | < -(REST)- > | frontend (JS) | |

| +----------------+ +---------------+ |

| |

+---------------------------------------------------+

Since the backend is Java based, I used a Maven default structure

(maven-archetype-site-simple):

project structure

1

2

3

4

5

6

7

8

9

1

0

1

1

1

├── _documentation

│   └── readme.txt

├── ngdemo.iml

├── pom.xml

└── src

└── main

├── java

│   └── ngdemo

│   ├── domain

│   │   └── User.java

│   ├── rest

│   │   └── UserRestService.java

│   └── service

│   └── UserService.java

Page 111: SPA AngularJS Draft

2

1

3

1

4

1

5

1

6

1

7

1

8

1

9

2

0

2

1

2

2

2

3

2

4

2

5

2

6

2

7

2

8

2

9

3

0

3

1

3

└── webapp

├── css

│   └── app.css

├── img

├── index-async.html

├── index.html

├── index.jsp

├── js

│   ├── app.js

│   ├── controllers.js

│   ├── directives.js

│   ├── filters.js

│   └── services.js

├── lib

│   └── angular

│   ├── angular-cookies.js

│   ├── angular-cookies.min.js

│   ├── angular.js

│   ├── angular-loader.js

│   ├── angular-loader.min.js

│   ├── angular.min.js

│   ├── angular-resource.js

│   ├── angular-resource.min.js

│   ├── angular-sanitize.js

│   ├── angular-sanitize.min.js

│   └── version.txt

├── partials

│   └── partial1.html

└── WEB-INF

└── web.xml

Page 112: SPA AngularJS Draft

2

3

3

3

4

3

5

3

6

3

7

3

8

3

9

4

0

4

1

4

2

4

3

4

4

src/main/java is the backend.

src/main/webapp/js is the frontend.

src/main/webapp/ also includes a copy of angular-seed.

RESTful web service (backend)Jersey is the Java reference implementation for providing REST.

Install the following dependencies in your pom.xml:

pom.xml

1<!-- .. -->

Page 113: SPA AngularJS Draft

2

3

4

5

6

7

8

9

1

0

1

1

1

2

1

3

1

4

1

5

1

6

1

7

1

8

<!-- RESTful web service: Jersey -->

<dependency>

<groupId>com.sun.jersey</groupId>

<artifactId>jersey-server</artifactId>

<version>1.17.1</version>

</dependency>

<dependency>

<groupId>com.sun.jersey</groupId>

<artifactId>jersey-servlet</artifactId>

<version>1.17.1</version>

</dependency>

<dependency>

<groupId>com.sun.jersey</groupId>

<artifactId>jersey-json</artifactId>

<version>1.17.1</version>

</dependency>

<!-- .. -->

Add the following servlet snippet to your web.xml:

web.xml

1

2

3

4

5

6

7

8

9

1

0

<!-- .. -->

<servlet>

<servlet-name>jersey-serlvet</servlet-name>

<servlet-class>

com.sun.jersey.spi.container.servlet.ServletContainer

</servlet-class>

<init-param>

<param-name>com.sun.jersey.config.property.packages</param-name>

<param-value>ngdemo.rest</param-value>

Page 114: SPA AngularJS Draft

1

1

1

2

1

3

1

4

1

5

1

6

1

7

1

8

1

9

2

0

2

1

2

2

2

3

2

4

2

5

2

6

</init-param>

<init-param>

<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>

<param-value>true</param-value>

</init-param>

<load-on-startup>1</load-on-startup>

</servlet>

<servlet-mapping>

<servlet-name>jersey-serlvet</servlet-name>

<url-pattern>/rest/*</url-pattern>

</servlet-mapping>

<!-- .. -->

Enough configuration for now: Create a simple User object…

User.java

1

2

3

4

5

package ngdemo.domain;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement

Page 115: SPA AngularJS Draft

6

7

8

9

1

0

1

1

1

2

1

3

1

4

1

5

1

6

1

7

1

8

1

9

2

0

2

1

2

2

2

3

2

4

2

5

2

6

public class User {

private String firstName;

private String lastName;

public String getFirstName() {

return firstName;

}

public void setFirstName(String firstName) {

this.firstName = firstName;

}

public String getLastName() {

return lastName;

}

public void setLastName(String lastName) {

this.lastName = lastName;

}

}

…and a service class…

Page 116: SPA AngularJS Draft

UserService.java

1

2

3

4

5

6

7

8

9

1

0

1

1

1

2

1

3

package ngdemo.service;

import ngdemo.domain.User;

public class UserService {

public User getDefaultUser() {

User user = new User();

user.setFirstName("JonFromREST");

user.setLastName("DoeFromREST");

return user;

}

}

…and finally the RESTful Service…:

UserRestService.java

1

2

3

4

5

6

7

8

9

1

0

1

1

1

2

1

3

package ngdemo.rest;

import ngdemo.domain.User;

import ngdemo.service.UserService;

import ngdemo.service.UserServiceImpl;

import javax.ws.rs.GET;

import javax.ws.rs.Path;

import javax.ws.rs.Produces;

import javax.ws.rs.core.MediaType;

@Path("/users")

public class UserRestService {

@GET

@Produces(MediaType.APPLICATION_JSON)

Page 117: SPA AngularJS Draft

1

4

1

5

1

6

1

7

1

8

1

9

2

0

2

1

2

2

public User getDefaultUserInJSON() {

UserService userService = new UserServiceImpl();

return userService.getDefaultUser();

}

}

Converting the User object to JSON

via @Produces(MediaType.APPLICATION_JSON) requires jersey-json

in web.xml (POJOMappingFeature).

Consuming web service from AngularJS (frontend)Don’t forget to add angular-resources.js to your index.html…

Consuming the web service:

services.js

1

2

3

4

5

var services = angular.module('ngdemo.services', ['ngResource']);

services.factory('UserFactory', function ($resource) {

return $resource('/ngdemo/rest/users', {}, {

query: {

Page 118: SPA AngularJS Draft

6

7

8

9

1

0

1

1

method: 'GET',

params: {},

isArray: false

}

})

});

Usage in controller:

controller.js

1

2

3

4

5

6

7

var app = angular.module('ngdemo.controllers', []);

app.controller('MyCtrl1', ['$scope', 'UserFactory', function ($scope, UserFactory) {

UserFactory.get({}, function (userFactory) {

$scope.firstname = userFactory.firstName;

})

}]);

Usage in view:

1

2

3

4

5

<div>

<p>

Result from RESTful service is: {{ firstname }}

</p>

</div>

Et voila:

Update (2013-07-18):

Page 119: SPA AngularJS Draft

You can clone a copy of this project

here: https://github.com/draptik/angulardemorestful.

To checkout the correct version for this demo, use the following

code:

1

2

3

git clone [email protected]:draptik/angulardemorestful.git

cd angulardemorestful

git checkout -f step1

In case you are not using git you can also download the project as

ZIP or tar.gz file

here: https://github.com/draptik/angulardemorestful/releases/tag/

step1

RESTful CRUD With AngularJSJUL 28TH, 2013

This post will show how to perform typical CRUD (create, read,

update and delete) operations in AngularJS when consuming a

RESTful web service.

A prerequisite for this demo is a working RESTful web service. For

a basic introduction on creating a Java based RESTful web service,

see my introduction on how to consume a RESTful web service

with AngularJS created by a Java backend. For completeness sake

I’ve added a Java based sample at the end of this post.

Frontend (AngularJS)

Views (Partials)

We will create three views.

The first view will display all users (user-list.html):

Page 120: SPA AngularJS Draft

The view also provides links to edit (ng-click="editUser(user.id)") and

delete (ng-click="deleteUser(user.id)") specific users as well as a link

to create a new user (ng-click="createUser()").1

2

3

4

5

6

7

8

9

1

0

1

1

1

2

1

3

1

<div class="span6">

<table class="table table-striped table-condensed">

<thead>

<tr>

<th style="min-width: 80px;">First name</th>

<th style="min-width: 80px;">Last name</th>

<th style="width:20px;"> </th>

<th style="width:20px;"> </th>

</tr>

</thead>

<tbody>

<tr ng-repeat="user in users">

<td>{{ user.firstName }}</td>

<td>{{ user.lastName }}</td>

<td><a ng-click="editUser(user.id)" class="btn btn-small btn-

primary">edit</a></td>

<td><a ng-click="deleteUser(user.id)" class="btn btn-small btn-

danger">delete</a></td>

Page 121: SPA AngularJS Draft

4

1

5

1

6

1

7

1

8

1

9

2

0

2

1

</tr>

</tbody>

</table>

<a ng-click="createNewUser()" class="btn btn-small">create new user</a>

</div>

The second and third view (user-detail.html and user-creation.html)

both provide a form for entering the user properties.

Page 122: SPA AngularJS Draft

They only differ in the actions provided. These actions

(cancel(), updateUser(), createNewUser()) are invoked using ng-click:

user-[detail|creation].html

1

2

3

4

5

6

7

8

9

<div class="container">

<h1>User detail</h1>

<form novalidate="novalidate" class="form-horizontal">

<div class="control-group">

<label class="control-label" for="inputFirstName">First name:</label>

<div class="controls">

<input type="text" id="inputFirstName" ng-model="user.firstName"/>

</div>

Page 123: SPA AngularJS Draft

1

0

1

1

1

2

1

3

1

4

1

5

1

6

1

7

1

8

1

9

2

0

2

1

2

2

2

3

2

4

2

5

2

6

2

7

2

8

</div>

<div class="control-group">

<label class="control-label" for="inputLastName">Last name:</label>

<div class="controls">

<input type="text" id="inputLastName" ng-model="user.lastName"/>

</div>

</div>

<div class="control-group">

<div class="controls">

<!-- user-detail.html: -->

<a ng-click="cancel()" class="btn btn-small">cancel</a>

<a ng-click="updateUser()" class="btn btn-small btn-primary">update

user</a>

<!-- user-creation.html: -->

<a ng-click="createNewUser()" class="btn btn-small btn-primary">create

new user</a>

</div>

</div>

</form>

</div>

Page 124: SPA AngularJS Draft

Controller

Next we will create three controllers corresponding to the three

views.

UserListCtrl

UserListCtrl provides three

functions editUser, deleteUser and createUser.

editUser and createUser merely redirect to a different partial view

using AngularJs’s $locationfunction.

deleteUser calls the UserFactory service method delete (which we will

create shortly).

Furthermore the $scope.users is filled with the result from

the UsersFactory.query() function.

Note that all required dependencies are injected into the

controller’s signature (function ($scope, UsersFactory, UserFactory,

$location)).

controller.js

1

2

3

4

5

6

7

8

9

1

0

1

1

1

2

1

3

1

var app = angular.module('ngdemo.controllers', []);

app.controller('UserListCtrl', ['$scope', 'UsersFactory', 'UserFactory', '$location',

function ($scope, UsersFactory, UserFactory, $location) {

// callback for ng-click 'editUser':

$scope.editUser = function (userId) {

$location.path('/user-detail/' + userId);

};

// callback for ng-click 'deleteUser':

$scope.deleteUser = function (userId) {

UserFactory.delete({ id: userId });

$scope.users = UsersFactory.query();

};

// callback for ng-click 'createUser':

$scope.createNewUser = function () {

Page 125: SPA AngularJS Draft

4

1

5

1

6

1

7

1

8

1

9

2

0

2

1

2

2

2

3

2

4

$location.path('/user-creation');

};

$scope.users = UsersFactory.query();

}]);

/* ... */

UserDetailCtrl and UserCreationCtrl

UserDetailCtrl provides the function udateUser, which in turn invokes

the service method UserFactory.update. The $scope.user is filled with

the result from calling UserFactory.show. cancel is just a convenient

link redirecting back to the user-list view.

UserCreationCtrl provides the function createNewUser,

calling UsersFactory.create.

Again, both controllers use $location to redirect back to the user-

list partial view.

controller.js

1

2

3

4

5

/* ... */

app.controller('UserDetailCtrl', ['$scope', '$routeParams', 'UserFactory', '$location',

function ($scope, $routeParams, UserFactory, $location) {

// callback for ng-click 'updateUser':

Page 126: SPA AngularJS Draft

6

7

8

9

1

0

1

1

1

2

1

3

1

4

1

5

1

6

1

7

1

8

1

9

2

0

2

1

2

2

2

3

2

4

2

5

2

6

2

7

$scope.updateUser = function () {

UserFactory.update($scope.user);

$location.path('/user-list');

};

// callback for ng-click 'cancel':

$scope.cancel = function () {

$location.path('/user-list');

};

$scope.user = UserFactory.show({id: $routeParams.id});

}]);

app.controller('UserCreationCtrl', ['$scope', 'UsersFactory', '$location',

function ($scope, UsersFactory, $location) {

// callback for ng-click 'createNewUser':

$scope.createNewUser = function () {

UsersFactory.create($scope.user);

$location.path('/user-list');

}

}]);

Page 127: SPA AngularJS Draft

Don’t forget to map the views to the corresponding controllers

in app.js using the $routeProvider:

app.js

1

2

3

4

5

6

7

angular.module('ngdemo', ['ngdemo.filters', 'ngdemo.services', 'ngdemo.directives',

'ngdemo.controllers']).

config(['$routeProvider', function ($routeProvider) {

$routeProvider.when('/user-list', {templateUrl: 'partials/user-list.html', controller:

'UserListCtrl'});

$routeProvider.when('/user-detail/:id', {templateUrl: 'partials/user-detail.html',

controller: 'UserDetailCtrl'});

$routeProvider.when('/user-creation', {templateUrl: 'partials/user-creation.html',

controller: 'UserCreationCtrl'});

$routeProvider.otherwise({redirectTo: '/user-list'});

}]);

Service

AngularJS can consume the web service using $resource. This

module is injected via 'ngResource'.

We create two factories:

UsersFactory (note the plural s) calls the web service with methods

not requiring an id (queryand create).

UserFactory calls the web service with methods requiring a user id

(show, update and delete).

services.js

1

2

3

4

5

6

7

8

9

1

0

var services = angular.module('ngdemo.services', ['ngResource']);

services.factory('UsersFactory', function ($resource) {

return $resource('/ngdemo/web/users', {}, {

query: { method: 'GET', isArray: true },

create: { method: 'POST' }

})

});

services.factory('UserFactory', function ($resource) {

return $resource('/ngdemo/web/users/:id', {}, {

Page 128: SPA AngularJS Draft

1

1

1

2

1

3

1

4

1

5

1

6

show: { method: 'GET' },

update: { method: 'PUT', params: {id: '@id'} },

delete: { method: 'DELETE', params: {id: '@id'} }

})

});

Backend (Java)

Here is an example of a RESTful web service created with Java:

UserRestService.java

1

2

3

4

5

6

7

8

9

1

0

1

1

1

2

1

3

1

4

1

5

1

package ngdemo.web.rest;

import com.google.inject.Inject;

import ngdemo.domain.User;

import ngdemo.service.contract.UserService;

import javax.ws.rs.*;

import javax.ws.rs.core.MediaType;

import java.util.List;

@Path("/users")

public class UserRestService {

private final UserService userService;

@Inject

public UserRestService(UserService userService) {

this.userService = userService;

}

@GET

@Produces(MediaType.APPLICATION_JSON)

Page 129: SPA AngularJS Draft

6

1

7

1

8

1

9

2

0

2

1

2

2

2

3

2

4

2

5

2

6

2

7

2

8

2

9

3

0

3

1

3

2

3

3

3

4

3

5

3

public List<User> getAllUsersInJSON() {

return userService.getAllUsers();

}

@GET

@Path("{id}")

@Produces(MediaType.APPLICATION_JSON)

public User getUserById(@PathParam("id") int id) {

return userService.getById(id);

}

@POST

@Consumes(MediaType.APPLICATION_JSON)

@Produces(MediaType.APPLICATION_JSON)

public User create(User user) {

return userService.createNewUser(user);

}

@PUT

@Path("{id}")

@Consumes(MediaType.APPLICATION_JSON)

@Produces(MediaType.APPLICATION_JSON)

public User update(User user) {

return userService.update(user);

}

@DELETE

@Path("{id}")

@Produces(MediaType.APPLICATION_JSON)

public void remove(@PathParam("id") int id) {

userService.remove(id);

}

}

Page 130: SPA AngularJS Draft

6

3

7

3

8

3

9

4

0

4

1

4

2

4

3

4

4

4

5

4

6

4

7

4

8

4

9

5

0

5

1

5

2

5

3

5

4

5

5

Page 131: SPA AngularJS Draft

You can clone a copy of this project

here: https://github.com/draptik/angulardemorestful.

To checkout the correct version for this demo, use the following

code:

1

2

3

git clone [email protected]:draptik/angulardemorestful.git

cd angulardemorestful

git checkout -f step4-angularjs-crud

In case you are not using git you can also download the project as

ZIP or tar.gz file

here: https://github.com/draptik/angulardemorestful/releases/tag/

step4-angularjs-crud

http://mobileappsresource.blogspot.in/2012/09/sample-application-with-angularjs.html

Sample Application with Angular.jsSample Application with Angular.js: After I blogged a three-part Backbone.js tutorial (part 1, part 2, part 3), a number of people asked me to try Angular.js. So I decided to take it for a test drive. I thought it would be interesting to rebuild with Angular.js the Wine Cellar application I had built with Backbone.

Page 132: SPA AngularJS Draft

If you are new to my Wine Cellar application, it is a simple CRUD app that allows you to manage (create, update, delete) wines in a Wine Cellar. The data is stored in a MySQL database that the client application accesses through a simple RESTful API. This seemed to be a good fit since CRUD applications are often positioned as the sweet spot for Angular.js.You can run the application here. The UI is intentionally plain to keep the focus on the key learning points. For obvious reasons, this online version is “read-only”. You can download the fully enabled version here. 

Application WalkthroughThe best way to get started with Angular.js is to go through the excellent tutorial that is part of the documentation, so I’ll only provide a high level overview of my code here. Like the Backbone.js implementation, the Angular.js version is a deep-linkable single page application. index.html is defined as follows:

<!DOCTYPE HTML><html xmlns:ng="http://angularjs.org"><head><title>Angular Cellar</title><link rel="stylesheet" href="css/styles.css" /></head>

<body ng:controller="RouteCtrl">

<div id="header">

Page 133: SPA AngularJS Draft

Angular Cellar <button ng:click="addWine()">New Wine</button></div>

<div id="sidebar"> <ng:include src="'tpl/wine-list.html'"></ng:include></div>

<div id="content"> <ng:view></ng:view></div>

<script src="lib/angular-0.9.19.min.js" ng:autobind></script><script src="js/services.js"></script><script src="js/controllers.js"></script>

</body>

</html>The application is driven by a set of Controllers that I defined in controllers.js as follows:

function RouteCtrl($route) {

var self = this;

$route.when('/wines', {template:'tpl/welcome.html'});

$route.when('/wines/:wineId', {template:'tpl/wine-details.html', controller:WineDetailCtrl});

$route.otherwise({redirectTo:'/wines'});

$route.onChange(function () { self.params = $route.current.params; });

$route.parent(this);

this.addWine = function () { window.location = "#/wines/add"; };

}

function WineListCtrl(Wine) {

this.wines = Wine.query();

}

function WineDetailCtrl(Wine) {

Page 134: SPA AngularJS Draft

this.wine = Wine.get({wineId:this.params.wineId});

this.saveWine = function () { if (this.wine.id > 0) this.wine.$update({wineId:this.wine.id}); else this.wine.$save(); window.location = "#/wines"; }

this.deleteWine = function () { this.wine.$delete({wineId:this.wine.id}, function() { alert('Wine ' + wine.name + ' deleted') window.location = "#/wines"; }); }

}RouteCtrl defines the routes of the application. Each route is defined by a template that is rendered in <ng:view> inside index.html. There can only be one <ng:view> in a document (more on that later). For example, here is the wine-list.html template:

<ul ng:controller="WineListCtrl"> <li ng:repeat="wine in wines"> <a href='#/wines/{{ wine.id }}'>{{ wine.name }}</a> </li></ul>The WineListCtrl and WineDetailCtrl controllers provide access to the data using a service defined in services.js as follows: 

angular.service('Wine', function ($resource) { return $resource('api/wines/:wineId', {}, { update: {method:'PUT'} });});

Services provide a great way to abstract your data access logic, and to easily change it without impacting the rest of the application. For example, you could easily change the Wine service to use a Mock service instead of a RESTful service.

ImpressionsI was able to build this application in a very limited amount of time with no prior knowledge of the framework. The data-binding implementation is nice, and, in general, the amount of boilerplate code you have to write is very limited. Frameworks are often a matter of style and personal preferences. Angular.js takes a more declarative approach than other frameworks. Based on this initial experience, I would also describe it as more prescriptive: I didn’t have to spend a lot of time wondering what was the best way to do things as Angular.js tends to have clear utilization patterns. I haven’t spend enough time with the framework to determine if that comes at the cost of less control, and I’d love to hear what other people are thinking.The only problem I ran into while building the application is the “one route / one view” coupling I alluded to above. As suggested in this thread, you can use <ng:include> to bind partials in the page.

Page 135: SPA AngularJS Draft

The same thread also indicates that multiple <ng:views> per route definition will be supported in the future. I was able to handle the simple UI requirements of this app using one <ng:view> and one <ng:include>. For more complex applications, I’d love the routing infrastructure to allow me to easily and arbitrarily add, remove, change, or animate different elements of the DOM when the route changes in order to support deeper UI transformations. I’m sure there are ways to do this. If Angular.js folks are reading this post, I’d love to hear what they think and what’s coming.

DownloadThe application is available on GitHub here. You will need the RESTful services to run this application. A PHP version (using the Slim framework) is available as part of the download. If you want to test the application with a Java back-end, you can download the Backbone version here, and reuse its JAX-RS back-end.

Angularjs Tutorial: Testing using ngMock $httpBackend and karma. Node REST testing with MochaIn Lesson 5, we implemented a node REST server to perform CRUD operations for device data. We have not yet hooked our server to mongodb, we will do that once we completely understand and unit test existing code base. This is all about Testing, Testing & more Testing. Client side testing using Karma & Server Side Node.js REST API testing using Mocha

Our existing unit test cases handle static data being returned by the services. Since we have refactored our code to use $resource & $http, our unit test cases need to be refactored to utilize _$httpBackend_ which is a mock API provided by angularjs. Understanding $httpBackend takes a while and getting used to. The general steps in testing controllers using httpBackend are:

1. Inject _$httpBackend_2. Use expectGet, expectPOST & expectPUT & respond API to implement mock backend behavior3. Run methods under test & verify results4. _$httpBackend_.flush() to flush pending requests on demand

Testing ControllersInjecting _$httpBackend_ into the tests:

  it('listDeviceController check for devices in the model',    inject(function(_$httpBackend_, $rootScope, $controller, Devices) {        var scope = $rootScope.$new();        var mockBackend = _$httpBackend_;

Implementing Mock Backend behavior:

        mockBackend.expectGET('http://localhost:3000/devices').          respond([{id:0, name: "iphone", assetTag:"a23456", owner:"dev", desc:"iOS4.2"}]);

Page 136: SPA AngularJS Draft

expectGET specifies the request expectation & respond implements the mock response

Run methods under test  controllerSpec.js: var ctrl = $controller('deviceListController', {$scope: scope}, Devices);

This creates the deviceListController. In the controller the following statement "$scope.devices = Devices.query()" does a query using the Devices service. Essentially, it makes a http GET request. This is intercepted by the ngMock angularjs module & its response is provided to the controller. 

Flush the response manually        mockBackend.flush();  

Test the conditions        expect(scope.devices).toEqualData([{id:0, name: "iphone", assetTag:"a23456", owner:"dev", desc:"iOS4.2"}]);

Here is the code for controller CRUD testing with ngMock httpBackend:

--

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636

46566676869707172737475767778798081828384858687

'use strict'; /* jasmine specs for controllers go here *//* Define all the services and controllers module, so they are accessable in your it's*/describe('controllers', function(){  beforeEach(function(){ module('cotd.controllers'); module('cotd.services'); module('ngResource');   this.addMatchers({

Page 137: SPA AngularJS Draft

toEqualData: function(expected) { return angular.equals(this.actual, expected); } }); });   it('listDeviceController check for devices in the model', inject(function(_$httpBackend_, $rootScope, $controller, Devices) { var scope = $rootScope.$new(); var mockBackend = _$httpBackend_;  mockBackend.expectGET('http://localhost:3000/devices'). respond([{id:0, name: "iphone", assetTag:"a23456", owner:"dev", desc:"iOS4.2"}]);  var ctrl = $controller('deviceListController', {$scope: scope}, Devices);  //expect(scope.devices).toBeUndefined(); mockBackend.flush();   // check the number of

Page 138: SPA AngularJS Draft

devices expect(scope.devices.length).toEqual(1); expect(scope.devices).toEqualData([{id:0, name: "iphone", assetTag:"a23456", owner:"dev", desc:"iOS4.2"}]); }));  it('addDeviceController should return correct http response in the model after controller.add', inject(function(_$httpBackend_, $rootScope, $controller, $location, Devices) { var scope = $rootScope.$new(); var mockBackend = _$httpBackend_;  mockBackend.expectPOST('http://localhost:3000/devices', {name: "iphone", assetTag:"a23456", owner:"dev", desc:"iOS4.2", id:1}). respond([{}]);  var ctrl = $controller('addDeviceController', {$scope: scope}, $location, Devices); var item = {name: "iphone", assetTag:"a23456", owner:"dev",

Page 139: SPA AngularJS Draft

desc:"iOS4.2", id:1};  scope.add(item); // make sure the flag is true expect(scope.add).toBeTruthy(); // check actual add effected the devices list //expect(Devices.query().length).toEqual(8); }));  it('editDeviceController should successfully edit devices in the model', inject(function(_$httpBackend_, $rootScope, $controller, $location, $routeParams, Devices) { var scope = $rootScope.$new(); var mockBackend = _$httpBackend_; var params = {}; params.id = 0;  mockBackend.expectGET('http://localhost:3000/devices/0', {"Accept":"application/json, text/plain, */*"}). respond({id:0, name: "iphone", assetTag:"a23456",

Page 140: SPA AngularJS Draft

owner:"qa", desc:"iOS4.3"});   var ctrl = $controller('editDeviceController', {$scope: scope, $routeParams: params},$location, Devices); var item = {id:0, name: "iphone-update", assetTag:"a23456", owner:"qa", desc:"iOS4.3"};  mockBackend.flush();  // testing for update flag expect(scope.add).toBeFalsy(); expect(scope.device.desc).toEqual("iOS4.3");  mockBackend.expectPUT('http://localhost:3000/devices/0', {"id":0,"name":"iphone-update","assetTag":"a23456","owner":"qa","desc":"iOS4.3"}). respond({});  scope.update(item);  mockBackend.flush(); })); 

Page 141: SPA AngularJS Draft

});

view raw controllerSpec.js  hosted with ❤ by GitHub

--

Testing ServicesTesting services is fairly straightforward. We are mainly ensuring that the services send the right http requests to the backend & expect the right responses. 

--

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585

96061626364656667

'use strict'; /* jasmine specs for services go here */ describe('service', function() { beforeEach(function(){ module('cotd.services'); module('ngResource'); });  describe('version', function() { it('should return current version', inject(function(version) { expect(version).toEqual('0.1'); })); });  describe('Devices', function() { it('should exist', inject(function(Devices){ expect(Devices).not.toBe(null); }));  it('should contain devices', inject(function(_$httpBacken

Page 142: SPA AngularJS Draft

d_, Devices) { var mockBackend = _$httpBackend_;  mockBackend.expectGET("http://localhost:3000/devices"). respond([{id:0, name: "iphone", assetTag:"a23456", owner:"dev", desc:"iOS4.2"}]);  var devices = Devices.query(); mockBackend.flush();   expect(devices.length).toEqual(1); }));  it('should send a POST request', inject(function(_$httpBackend_, Devices) { var item = {id:7, name: "iphone", assetTag:"a23456", owner:"dev", desc:"iOS4.2"}; var mockBackend = _$httpBackend_;  var newDevice = new Devices(item);  mockBackend.expectPOST("http://localhost:3000/devices", {id:7, name: "iphone", assetTag:"a23456", owner:"dev", desc:"iOS4.2"}).respond({});  newDevice.$save(); mockBackend.flush();

Page 143: SPA AngularJS Draft

  }));  it('should send a PUT request', inject(function(_$httpBackend_, Devices) { var mockBackend = _$httpBackend_;  mockBackend.expectPUT('http://localhost:3000/devices/0', {"id":0,"name":"iphone-update","assetTag":"a23456","owner":"dev","desc":"iOS4.3"}). respond({});  // modified device name test var item = {id:0, name: "iphone-update", assetTag:"a23456", owner:"dev", desc:"iOS4.3"}; Devices.update({deviceId:0},item);  mockBackend.flush(); }));  });  });

view raw servicesSpec.js  hosted with ❤ by GitHub

--

Trouble-shooting:

Error: Unknown provider: $resourceProvider <- devices="" div="" resource="">

Page 144: SPA AngularJS Draft

  ngResource is not part of angularjs core. So, you have to include it specifically in your test specs, like so: 

describe('service', function() {

  beforeEach(function(){

    module('cotd.services');

    module('ngResource');

  });

Testing the server - Node REST service testing using Mocha, Chai &supertestNow that we have extensively implemented client side unit testing specs, the focus naturally turns to testing the server side. After reviewing a bunch of server side testing frameworks, i think Mocha provides for a better suite since it allows for BDD a.k.a jasmine style syntax. This allows us to keep the testing constructs fairly consistent between client & server. Lets implement hands on mocha testing for our server.

We can accomplish Server side REST based testing easily by combining 3 frameworks Mocha, Chai & SuperTest. They play well nicely and makes it easier to write Node Based REST tests. 

Step 1: is to add mocha, Chai & supertest to package.json

{  "name": "cotd-server",  "description": "cotd backend",  "version": "0.0.1",  "private": "true",  "dependencies": {    "express": "3.2.2",    "cors": "*"  },  "devDependencies":{    "mocha": "*",    "chai": "*",    "supertest": "*"  },  "scripts":{     "test": "mocha"  }}

Step 2: export the express app as a module in server.js. This is for Mocha to test the server functionality without running the server first.

Page 145: SPA AngularJS Draft

module.exports = app; 

Step 3: create a test directory in your server folder and Create a new file for the test spec called test-devicesRest.js. Require mocha, chai & supertest in your test spec.

var chai = require('chai'),    express = require('express'),    request = require('supertest');

var app = require('../server');

var expect = chai.expect;

Step 4: writing a GET test

describe('GET /devices', function(){    it('should return 200 and JSON with valid keys', function(done){        request(app)        .get('/devices')        .end(function(err, res){            //validate the keys in the response JSON matches, we dont care about the values            expect(res.status).to.equal(200);            expect(res.body[0]).to.have.keys(['id', 'name', 'assetTag', 'owner', 'desc']);            done();        });    });   });

Step 5: creating a simple Makefile to run our test using Mocha. running make test on the command line should run mocha. It looks for the test directory and executes test specs within it.

REPORTER = list#REPORTER = dot

test: @./node_modules/.bin/mocha \ --reporter $(REPORTER)

test-w: @./node_modules/.bin/mocha \ --reporter $(REPORTER) \ --growl \ --watch

.PHONY: test

Page 146: SPA AngularJS Draft

Step 6: Write other tests. Here is a complete source code for our REST tests--

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666

768697071727374

var chai = require('chai'), express = require('express'), request = require('supertest'); var app = require('../server'); var expect = chai.expect;  describe('GET /devices', function(){ it('should return 200 and JSON with valid keys', function(done){ request(app) .get('/devices') .end(function(err, res){ //validate the keys in the response JSON matches, we dont care about the values expect(res.status).to.equal(200); expect(res.body[0]).to.have.keys(['id', 'name', 'assetTag', 'owner', 'desc']); done();

Page 147: SPA AngularJS Draft

}); }); }); describe('GET /devices/0', function(){ it('should return 200 and JSON with valid keys', function(done){ request(app) .get('/devices/0') .end(function(err, res){ //validate the keys in the response JSON matches, we dont care about the values expect(res.status).to.equal(200); expect(res.body).to.have.keys(['id', 'name', 'assetTag', 'owner', 'desc']); done(); }); }); }); describe('POST /devices', function(){ it('should return 200 and status JSON have valid status', function(done){ request(app)

Page 148: SPA AngularJS Draft

.post('/devices') .send({id:7, name: "iphone", assetTag:"a73856", owner:"dev", desc:"iOS5"}) .end(function(err, res){ //validate the keys in the response JSON matches, we dont care about the values expect(res.status).to.equal(200); expect(res.body).to.deep.equal({status: '1'}); done(); }); }); }); describe('PUT /devices/0', function(){ it('should return 200 and status JSON have valid status', function(done){ request(app) .put('/devices/0') .send({id:0, name: "iphone", assetTag:"a73856", owner:"dev", desc:"iOS5"}) .end(function(err, res){

Page 149: SPA AngularJS Draft

//validate the keys in the response JSON matches, we dont care about the values expect(res.status).to.equal(200); expect(res.body).to.deep.equal({status: '1'}); done(); }); }); }); describe('Delete /devices/0', function(){ it('should return 200 and status JSON have valid status', function(done){ request(app) .del('/devices/0') .end(function(err, res){ //validate the keys in the response JSON matches, we dont care about the values expect(res.status).to.equal(200); expect(res.body).to.deep.equal({status: '1'}); done(); });

Page 150: SPA AngularJS Draft

}); });

view raw test-devicesREST.js  hosted with ❤ by GitHub

--

REST: CRUD with JAX-RS (Jersey)In an earlier post I've discussed setting up Tomcat and Eclipse environment for JAX-RS. This post is an attempt to discuss some more basics of JAX-RS, specifically performing CRUD operations.

Prerequisites Setup environment, discussed in this post

Commons-HttpClient is used for the client program. Commons-codec and

Commons-logging are its dependencies. All of them can be downloaded

from Apache Commons website. Put those jars in the web application's lib.

Now some funIf you are remotely interested in REST read Roy Fielding's dissertation on the topic. The chapter on RESTis a must read, not necessary to understand this exercise but strongly recommended to gain a big picture.As a part of the CRUD (creating, reading, updating and deleting) exercise let's try and create a Customer resource, retrieve Customer details, update the details and finally delete the Customer. To keep it simple and to keep the focus on the topic at hand I will not use a real database, instead use a file system leveraging Java's Properties mechanism.

Our customer POJO has got 4 properties: id, first name, last name and a zip code.

01public class Customer {

02  

03private Integer customerId;

04  

05private String firstName;

06  

07private String lastName;

08  

Page 151: SPA AngularJS Draft

09private String zipcode;

10  

11

//setters and getters

12 }

CreateLet's start with CustomerResource class. A resource class is a Java class that uses JAX-RS annotations to implement corresponding Web resource. According to the specification, resource classes are POJOs that have at least one method annotated with @Path or a request method designator.

01@Path ("customer")

02public class CustomerResource {

03

public static final String DATA_FILE = "C:\\TEMP\\customer-data.txt";

04  

05 @POST

06@Consumes ("application/xml")

07

public Response addCustomer(InputStream customerData) {

08 try {

09

Customer customer = buildCustomer(null, customerData);

10 long customerId = persist(customer, 

Page 152: SPA AngularJS Draft

0);

11return Response.created(URI.create("/" + customerId)).build();

12} catch (Exception e) {

13

throw new WebApplicationException(e, Response.Status.INTERNAL_SERVER_ERROR);

14 }

15 }

Paths are relative. For an annotated class the base URI is the application context.

For an annotated method the base URI is the effective URI of the contatining class.

Base URIs are treated as if they ended in "/". So in the above example first line

indicates how the Customer URI is mapped to/customer.

addCustomer method is annotated as a method that responds to the HTTP POST

method calls. As there is no @Path annotation on the method, the URI of the class is

also the URI to access the method.

Another important annotation is Consumes. It defines the media types that the

methods of a resource class can accept. If not specified, it is assumed that any

media type is acceptable. We don't have a Consumes annotation at the class level in

this example, but if there is one the method level annotation takes precedence over

the class level annotation.

Response is returned to the client which contains a URI to the newly created

resource. Return type Response results in an entity body mapped from the entity

property of the Response with the status code specified by the status property of the

response.

WebApplicationException is a RuntimeException that is used to wrap the appropriate

HTTP status codes.

addCustomer method builds the customer from the received XML input and persists

it. Code for the methods called in addMethod() is provided below and is self-

explanatory. These methods are used for both create and update purposes and

hence the method signatures take Customer as a parameter.

01

private long persist(Customer customer, long customerId) throws IOException {

02 Properties properties = new Properties(

Page 153: SPA AngularJS Draft

);

03properties.load(new FileInputStream(DATA_FILE));

04  

05if (customerId == 0) {

06

customerId = System.currentTimeMillis();

07 }

08  

09properties.setProperty(String.valueOf(customerId),

10

customer.getFirstName() + "," + customer.getLastName() +

11

"," + customer.getZipcode());

12properties.store(new FileOutputStream(DATA_FILE), null);

13return customerId;

14 }

15  

16

private Customer buildCustomer(Customer customer, InputStream customerData)

17throws ParserConfigurationException, SAXException, IOException {

18 if (customer == null)

Page 154: SPA AngularJS Draft

{

19

customer = new Customer();

20 }

21

DocumentBuilder documentBuilder =

22DocumentBuilderFactory.newInstance().newDocumentBuilder();

23

Document document = documentBuilder.parse(customerData);

24document.getDocumentElement().normalize();

25  

26

NodeList nodeList = document.getElementsByTagName("customer");

27  

28

Node customerRoot = nodeList.item(0);

29if (customerRoot.getNodeType() == Node.ELEMENT_NODE) {

30

Element element = (Element) customerRoot;

31

NodeList childNodes = element.getChildNodes();

32 for (int i = 0; i <

Page 155: SPA AngularJS Draft

childNodes.getLength(); i++) {

33

Element childElement = (Element)childNodes.item(i);

34

String tagName = childElement.getTagName();

35

String textContent = childElement.getTextContent();

36if (tagName.equals("firstName")) {

37customer.setFirstName(textContent);

38} else if (tagName.equals("lastName")) {

39customer.setLastName(textContent);

40} else if (tagName.equals("zipcode")) {

41customer.setZipcode(textContent);

42 }

43 }

44} else {

45

throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);

46 }

47  

48return customer;

49 }

Page 156: SPA AngularJS Draft

Test itA test client method to test add operation looks something like the following, you may run this as a Java application via a main() method or it is easy to modify the following as a Junit test case.

01private static void testAddCustomer() throws IOException, HttpException {

02

final String addCustomerXML =

03"<customer>" +

04"<firstname>Joe</firstname>" +

05"<lastname>Schmo</lastname>" +

06"<zipcode>98042</zipcode>" +

07"</customer>";

08  

09

PostMethod postMethod = new PostMethod(

10"http://localhost:9000/RestExample/customer");

11

RequestEntity entity = new InputStreamRequestEntity(

12new ByteArrayInputStream(addCustomerXML.getBytes()),

13"application/xml");

14 postMethod.setRequestEntity(entit

Page 157: SPA AngularJS Draft

y);

15

HttpClient client = new HttpClient();

16 try {

17

int result = client.executeMethod(postMethod);

18

System.out.println("Response status code: " + result);

19System.out.println("Response headers:");

20

Header[] headers = postMethod.getResponseHeaders();

21

for (int i = 0; i < headers.length; i++) {

22System.out.println(headers[i].toString());

23} finally {

24postMethod.releaseConnection();

25 }

26 }

Output

Response status code: 201Response headers:Server: Apache-Coyote/1.1Location: http://localhost:9000/RestExample/customer/1236708444823Content-Length: 0Date: Thu, 05 Mar 2009 12:15:22 GMT

Page 158: SPA AngularJS Draft

Response status code 201 indicates the resource was created

Location header displays the URI of the new resource that is created

ReadretrieveCustomer() method below illustrates the read operation:

01 @GET

02@Path ("{id}")

03@Produces ("application/xml")

04

public StreamingOutput retrieveCustomer(@PathParam ("id") String customerId) {

05 try {

06

String customerDetails = loadCustomer(customerId);

07

System.out.println("customerDetails: " + customerDetails);

08if (customerDetails == null) {

09throw new NotFoundException("<error>No customer with id: " +

10

customerId + "</error>");

11 }

12  

13

final String[] details = customerDetails.split(",");

14  

15 return new StreamingOutput

Page 159: SPA AngularJS Draft

() {

16public void write(OutputStream outputStream) {

17

PrintWriter out = new PrintWriter(outputStream);

18

out.println("< ?xml version=\"1.0\" encoding=\"UTF-8\"?>");

19out.println("<customer>");

20

out.println("<firstname>" + details[0] + "</firstname>");

21

out.println("<lastname>" + details[1] + "</lastname>");

22

out.println("<zipcode>" + details[2] + "</zipcode>");

23out.println("</customer>");

24out.close();

25 }

26 };

27} catch (IOException e) {

28throw new WebApplicationException(e,

29Response.Status.INTERNAL_SERVER_ERROR);

Page 160: SPA AngularJS Draft

30 }

31 }

Get annotation indicates that this method is responsible for HTTP GET operations

Path annotation indicates a dynamic id. As discussed above the paths are relative,

so the URI /customer/{id} is the resultant path for this method

Produces annotation, indicates the media type that is resulted from this operation

PathParam annotation in the parameter reads the path id that is passed using the

Path annotation

StreamingOutput is returned by this resource method. StreamingOutput is a simpler

version ofMessageBodyWriter. It has a write() method that has Output stream. All

that you need is to write the data into that object, which will be returned to the client

program.

Test itIn a web browser you may try the URI that was resulted from our create operation above (http://localhost:9000/RestExample/customer/1236708444823 for this example).

OutputYou should see response something like the followiing:

1

< ?xml version="1.0" encoding="UTF-8" ?>

2

- <customer>

3<firstname>Joe</firstname>

4<lastname>Schmo</lastname>

5<zipcode>98042</zipcode>

6</customer>

UpdatePOST is used create a new resource, PUT method updates the state of a known resource. You often see discussions about when to use POST vs PUT. My understanding is that if you are trying to create a brand new resource use POST, no Request-URI is required for POST. State is sent as a part of the BODY and the server

Page 161: SPA AngularJS Draft

should return you back HTTP code 201 (resource created), just like what we discussed in the CREATE section above. On the other hand, if you're updating the state of a resource use PUT. In this case you need the URI to the resource that you are trying to update.

Update code follows:

01 @PUT

02@Path("{id}")

03@Consumes("application/xml")

04public void updateCustomer(@PathParam("id") String customerId,

05InputStream input) {

06 try {

07

String customerDetails = loadCustomer(customerId);

08if (customerDetails == null) {

09throw new WebApplicationException(Response.Status.NOT_FOUND);

10 }

11

String[] details = customerDetails.split(",");

12

Customer customer = new Customer();

13customer.setFirstName(details[0]);

14customer.setLastName(details[1]);

15 customer.setZipcode(details

Page 162: SPA AngularJS Draft

[2]);

16buildCustomer(customer, input);

17

persist(customer, Long.valueOf(customerId));

18} catch (Exception e) {

19throw new WebApplicationException(e,

20Response.Status.INTERNAL_SERVER_ERROR);

21 }

22 }

PUT annotation marks the method as a resource method that handles HTTP PUT

requests

Path and Consumes annotations are already discussed in the earlier sections

Test itUsing HttpClient the update test can be performed as follows. In this example zip code of a customer is being updated:

01private static void testUpdateCustomer() throws IOException, HttpException {

02

final String addCustomerXML =

03"<customer>" +

04"<zipcode>98043</zipcode>" +

05"</customer>";

06  

07 PutMethod putMethod = new PutMethod

Page 163: SPA AngularJS Draft

(

08"http://localhost:9000/RestExample/customer/1236708444823");

09

RequestEntity entity = new InputStreamRequestEntity(

10new ByteArrayInputStream(addCustomerXML.getBytes()),

11"application/xml");

12putMethod.setRequestEntity(entity);

13

HttpClient client = new HttpClient();

14 try {

15

int result = client.executeMethod(putMethod);

16

System.out.println("Response status code: " + result);

17System.out.println("Response headers:");

18

Header[] headers = putMethod.getResponseHeaders();

19

for (int i = 0; i < headers.length; i++) {

20System.out.println(headers[i].toString());

21 }

22 } finally 

Page 164: SPA AngularJS Draft

{

23putMethod.releaseConnection();

24 }

25 }

DeleteThe HTTP DELETE method requests the server to delete the resource identified by the request-URI.

01 @DELETE

02@Path("{id}")

03public void deleteCustomer(@PathParam("id") String customerId) {

04 try {

05

Properties properties = new Properties();

06properties.load(new FileInputStream(DATA_FILE));

07

String customerDetails = properties.getProperty(customerId);

08if (customerDetails == null) {

09throw new WebApplicationException(Response.Status.NOT_FOUND);

10 }

11properties.remove(customerId);

12

properties.store(new FileOutputStream(DATA_FILE), null);                       

13 } catch (Exceptio

Page 165: SPA AngularJS Draft

n e) {

14

throw new WebApplicationException(e, Response.Status.INTERNAL_SERVER_ERROR);

15 }              

16 }

DELETE annotation is used to mark the method as a resource method that handles

the resource-delete operation.

Test itTest code for Delete. Attempting to delete the customer resource created earlier:

01private static void testDeleteCustomer() throws HttpException, IOException {

02

DeleteMethod deleteMethod = new DeleteMethod(

03"http://localhost:9000/RestExample/customer/1236708444823");

04

HttpClient client = new HttpClient();

05 try {

06

int result = client.executeMethod(deleteMethod);

07

System.out.println("Response status code: " + result);

08

System.out.println("Response headers:");           

09

Header[] headers = deleteMethod.getResponseHeaders();

10 for (int i

Page 166: SPA AngularJS Draft

= 0; i < headers.length; i++) {

11System.out.println(headers[i].toString());

12 }

13} finally {

14deleteMethod.releaseConnection();

15 }  

16 }

outputStatus code 204 is returned, stands for No Content. This code is used in cases where the request is successfully processed, but the response doesn't have a message body

Response status code: 204Response headers:Server: Apache-Coyote/1.1Date: Tue, 10 Mar 2009 18:34:46 GMTBe Sociable, Share!

http://www.manning.com/mikowski/SPWA_meap_ch01.pdf

One reason traditional websites are slow is because popular MVC server frameworks are focused on serving page after page of static content to an essentially dumb client. When we click a link in a traditional website slideshow, for example, the screen flashes white and everything reloads over several seconds:the navigation, ads, headlines, text, and footer are all rendered again. Yet the only thing that changes is the slideshow image and perhaps the description text. Worse, there’s no indicator when some element of the page becomes functional. For example, sometimes a link can be clicked on as soon as it appears on a web page; other times we have to wait until the redrawing is 100% complete plus five seconds. This slow, inconsistent, and clunky experience is becoming unacceptable for an increasingly sophisticated web consumer.Product design is increasingly seen as the decisive factor in the success of commercial and enterprise web applications. SPAs are often the best choice to provide the optimal user experience. As a result, we expect the demand for user-focused design to drive SPA adoption and sophistication.SPA DefinitionAn SPA is an application delivered to the browser that doesn’t reload the page during use. Like all applications, it’s intended to help the user complete a task, such as “write a document” or “administer a web server.” We can think of an SPA as a fat client that’s loaded from a web server.