angularjs get started and miscellaneous - codeproject

34
Articles » Languages » Java » General Dr. Song Li, 30 Aug 2015 CPOL 1.7K 22 8 AngularJS Get Started and Miscellaneous This is a study note on Angular. I realized that Angular is a larger topic than I initially thought of. I hope I can be concise enough to cover a few interesting aspects in as few sentences as possible. Download AngularExample.zip - 13.9 KB Introduction This is a study note on Angular. I realized that Angular is a larger topic than I initially thought of. I hope I can be concise enough to cover a few interesting aspects in as few sentences as possible. Background When working on web applications, I found that it would be great if I can get the following capabilities either from Javascript itself or from some third party libraries: Javascript is not like C# or Java, it does not natively support namespaces/packages. When a Javascript program gets reasonably complex, it is very common to have name collisions; 5.00 (1 vote) AngularJS Get Started and Miscellaneous - CodeProject http://www.codeproject.com/Articles/1022023/AngularJS-Get-Started-and-Miscellaneous?disp... 1 of 34 31/08/2015 15:07

Upload: gfgomes

Post on 14-Dec-2015

25 views

Category:

Documents


0 download

DESCRIPTION

AngularJS Get Started and Miscellaneous - CodeProject

TRANSCRIPT

Articles » Languages » Java » General

Dr. Song Li, 30 Aug 2015 CPOL 1.7K 22 8

AngularJS Get Started and Miscellaneous

This is a study note on Angular. I realized that Angular is a larger topic than I initially thought of. I hope I can be

concise enough to cover a few interesting aspects in as few sentences as possible.

Download AngularExample.zip - 13.9 KB

Introduction

This is a study note on Angular. I realized that Angular is a larger topic than I initially thought of. I hope I can be

concise enough to cover a few interesting aspects in as few sentences as possible.

Background

When working on web applications, I found that it would be great if I can get the following capabilities either

from Javascript itself or from some third party libraries:

Javascript is not like C# or Java, it does not natively support namespaces/packages. When a Javascript

program gets reasonably complex, it is very common to have name collisions;

5.00 (1 vote)

AngularJS Get Started and Miscellaneous - CodeProject http://www.codeproject.com/Articles/1022023/AngularJS-Get-Started-and-Miscellaneous?disp...

1 of 34 31/08/2015 15:07

In a single page web application, Ajax calls are used extensively. It would be nice that I can easily get a

JSON object with the data from the UI to send to the server. When an Ajax call receives the data from the

server, it would also be nice if I can easily update the UI without working on each HTML element.

According to the Angular web site, Angular fits the requirements nicely. The module structure and the

dependency injection mechanism solve the name collision problem, while the two way binding capability helps

me to synchronize the UI and the data. In order to familiarize myself with Angular, I prepared this study note.

Hopefully it will help you to understand Angular too.

The attached file is a Java Maven project. If you use Java, it is great, and you can simply download it and import

it into Eclipse to run it. If you do not use Java, it is not a problem. The project only has HTML files. You can just

AngularJS Get Started and Miscellaneous - CodeProject http://www.codeproject.com/Articles/1022023/AngularJS-Get-Started-and-Miscellaneous?disp...

2 of 34 31/08/2015 15:07

get the HTML files and load them into the browser. My recommendation is that it is better to put the HTML files

on a web server and load it from the server to avoid the browser's security checks. You can use Tomcat, IIS,

Node.js, and whatever servers that you are comfort with. The Javascript library for Angular in the examples is

linked from the google CDN. If you want to run the examples by yourself, please make sure your computer has

internet access, so your browser can download the Angular Javascript file. The "index.html" page contains the

HTTP links to all the examples.

The examples are not intended to serve as a comprehensive document for Angular. If you want

the comprehensive document, you can go to the Angular web page.

1. basic-bootstrap.html

This example is to demonstrate how Angular takes control of the web pages or part of the web pages. In

Angular terminology, this process is called "bootstrap". This example also tries to answer the following basic

start-up questions:

Where is an Angular data model?

How is the data model related to the HTML elements?

How do the user activities like button clicks affect the data model and the UI?

<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Angular Basic example</title><link rel="stylesheet" type="text/css" href="styles/app.css">

AngularJS Get Started and Miscellaneous - CodeProject http://www.codeproject.com/Articles/1022023/AngularJS-Get-Started-and-Miscellaneous?disp...

3 of 34 31/08/2015 15:07

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script><script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.min.js"></script> <script type="text/javascript">

var myApp = angular.module('myApp', []); myApp.controller('MyController', ['$scope', function ($scope) { $scope.no = 0; $scope.data = {greeting: 'Hello World'}; $scope.sayHello = function() { $scope.no = $scope.no + 1; $scope.data = {greeting: 'Hello World No.' + $scope.no}; }; }]); angular.element(document).ready(function() {

var element = document.getElementById('divManuBootstrap-angular'); angular.bootstrap(element, ['myApp'], {strictDi: true}); }); $(document).ready(function() {

var element = document.getElementById('divManuBootstrap-jQuery'); angular.bootstrap(element, ['myApp'], {strictDi: true}); }) </script></head><body><div id="divAutomaticInitialization" ng-app="myApp" ng-strict-di>

<div ng-controller="MyController"><span>{{data.greeting}}</span><button type="button" ng-click="sayHello()">Say hello...</button>

</div></div><div id="divManuBootstrap-angular">

<div ng-controller="MyController" ng-strict-di><span>{{data.greeting}}</span><button type="button" ng-click="sayHello()">Say hello...</button>

</div></div><div id="divManuBootstrap-jQuery">

<div ng-controller="MyController" ng-strict-di><span>{{data.greeting}}</span><button type="button" ng-click="sayHello()">Say hello...</button>

</div></div>

AngularJS Get Started and Miscellaneous - CodeProject http://www.codeproject.com/Articles/1022023/AngularJS-Get-Started-and-Miscellaneous?disp...

4 of 34 31/08/2015 15:07

<br><div><a href="index.html">Back...</a></div></body></html>

You may notice that this example linked both Angular and jQuery in the web page. According to the Angular

documentation:

Angular can use jQuery if it's present in the app when the application is being bootstrapped;

If jQuery is not present in the script path, Angular falls back to its own implementation of the subset of

jQuery that Angular calls jQLite.

Since we linked the "angular.min.js" file in the web page, it will be executed after the web page is loaded. It will

create an object called "angular". The "angular" object is the primary reference that we can use to access the

Angular functionalities. The "angular.module()" method creates an Angular module. We will talk about more

about Angular modules in the next example. For now, we can just think of an Angular module being the angular

way of grouping our code.

In the above code, I added a controller to the "myApp" module. In Angular, a controller is a function that

will be executed when binding the data model to the HTML UI elements;

In the standard Angular syntax, a controller will be passed in a variable "$scope". The "$scope" variable is

the Angular data model that we can add both data and function properties to it.

We have two ways to bind the data model "$scope" to the HTML elements, they are automatic bootstrap and

manual bootstrap.

The "DIV" element with id "divAutomaticInitialization" is automatically bootstrapped. In order to set up an

automatically bootstrap, we need to specify the "ng-app" and "ng-controller" attributes to tell Angular

which module and controller to use to bind to the HTML elements. In the HTML elements, we will also

need to tell Angular which data or function property is associated to which HTML element. For example,

the "sayHello()" function is associated to the button click event though "ng-click" attribute. The angular

specific custom HTML attributes like "ng-app", "ng-controller", and "ng-click" are called directives;

The "DIV" element with id "divManuBootstrap-angular" is manually bootstrapped in the document's ready

event captured by the Angular syntax "angular.element(document)". We can call the "angular.bootstrap()"

method and tell it the HTML element and the Angular module to initiate the bootstrap;

The "DIV" element with id "divManuBootstrap-jQuery" is also manually bootstrapped. But it is

bootstrapped in the document's ready event captured by the standard jQuery syntax "$(document)".

AngularJS Get Started and Miscellaneous - CodeProject http://www.codeproject.com/Articles/1022023/AngularJS-Get-Started-and-Miscellaneous?disp...

5 of 34 31/08/2015 15:07

By loading the example into a web browser and clicking on each of the buttons a couple of times, we will notice

the following:

Angular does work well with jQuery. In this example, even we used the Angular syntax

"angular.element(document)", we are virtually calling the jQuery to capture the document's ready event;

When we click on each of the "Say hello..." buttons, we will notice that the "$scope.sayHello()" function is

called, and the data on the "$scope" is updated. Angular also helped us to have the text in the "<span>"

element updated on the UI;

When we click on each of the "Say hello..." buttons, we can also notice that only the text next to the

button is updated. This means that the "$scope" object is created for each controller binding, not for each

controller. Although we have only one controller, but it is bound three times to three different "DIV"

elements, so we have three independent "$scope" objects in the Angular context in the web page.

If we open the firebug to take a look at the network traffic, we will see that Angular file size is almost twice as

large as jQuery. Since Angular does use jQuery and also implements its own jQLite, and since Angular

AngularJS Get Started and Miscellaneous - CodeProject http://www.codeproject.com/Articles/1022023/AngularJS-Get-Started-and-Miscellaneous?disp...

6 of 34 31/08/2015 15:07

document does mention that on relatively lower level operations, jQuery can do better job than Angular, I think

that it would be nice if Angular can come up two versions, one with jQLite and one without it. If we want to use

jQuery, we can choose the version without the jQLite, so the users will have a smaller Angular to download.

2.basic-module-and-di.html

Angular groups the application code in modules, which kind of serves the namespace/package functionalities in

C# and Java, although it is verbose compared with the concise C# and Java. Angular also has a dependency

injection mechanism, so the Angular objects are not created by the application code. Instead, they are injected

by Angular when we need them.

<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Angular Basic example</title><link rel="stylesheet" type="text/css" href="styles/app.css"> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.min.js"></script> <script type="text/javascript">

// Declare the modulesvar dataModule = angular.module('dataModule', []);var dataManipulationModuleByService = angular

.module('dataManipulationModuleByService', ['dataModule']);var dataManipulationModuleByProvider = angular

.module('dataManipulationModuleByProvider', ['dataModule']);var AppModule = angular.module('AppModule',

['dataModule', 'dataManipulationModuleByService', 'dataManipulationModuleByProvider']);

// Add a factory to the 'dataModule' module dataModule.factory('appData', function() {

return {no: 0, greeting: 'Hello World'}; });

// Add a service to the 'dataManipulationModuleByService' module dataManipulationModuleByService.service('appDataManipulatorByService', ['appData', function(data) {

this.increaseGreeting = function() { data.no = data.no + 1; data.greeting = 'Hello World No.' + data.no; }; }]);

AngularJS Get Started and Miscellaneous - CodeProject http://www.codeproject.com/Articles/1022023/AngularJS-Get-Started-and-Miscellaneous?disp...

7 of 34 31/08/2015 15:07

// Add a provider to the 'dataManipulationModuleByProvider' module dataManipulationModuleByProvider.provider('appDataManipulatorByProvider', function() {

var greetingText = null;this.setGreetingText = function(text) { greetingText = text; };

this.$get = ['appData', function(data) {

return { decreaseGreeting: function() { data.no = data.no - 1; data.greeting = greetingText + data.no; } }; }]; }).config(["appDataManipulatorByProviderProvider", function(provider) { provider.setGreetingText('Hello World No.'); }]);

// Use the modules in the 'AppModule' module AppModule.controller('MyController', ['$scope', 'appData', 'appDataManipulatorByService', 'appDataManipulatorByProvider',

function ($scope, data, sManipulator, pManipulator) { $scope.data = data; $scope.addGreeting = function() { sManipulator.increaseGreeting(); }; $scope.decreaseGreeting = function() { pManipulator.decreaseGreeting(); } }]); angular.element(document).ready(function() { angular.bootstrap(document.getElementById('divManuBootstrap-angular'), ['AppModule'], {strictDi: true}); });</script></head><body><div id="divAutomaticInitialization" ng-app="AppModule" ng-strict-di>

<div ng-controller="MyController"><span>{{data.greeting}}</span><button type="button" ng-click="addGreeting()">Add hello...</button><button type="button" ng-click="decreaseGreeting()">Decrease hello...</button>

</div><div ng-controller="MyController">

<span>{{data.greeting}}</span><button type="button" ng-click="addGreeting()">Add hello...</button><button type="button" ng-click="decreaseGreeting()">Decrease hello...</button>

</div>

AngularJS Get Started and Miscellaneous - CodeProject http://www.codeproject.com/Articles/1022023/AngularJS-Get-Started-and-Miscellaneous?disp...

8 of 34 31/08/2015 15:07

</div> <div id="divManuBootstrap-angular">

<div ng-controller="MyController" ng-strict-di><span>{{data.greeting}}</span><button type="button" ng-click="addGreeting()">Add hello...</button><button type="button" ng-click="decreaseGreeting()">Decrease hello...</button>

</div></div><br><div><a href="index.html">Back...</a></div></body></html>

Angular modules are created by "angular.module('module name', [An array of module names that this module

depends on])" syntax. In this example, we have 4 modules.

The "dataModule" module has no dependency module;

The "dataManipulationModuleByService" depends on objects from the "dataModule" module;

The "dataManipulationModuleByProvider" dependes on objects from the "dataModule" module;

The "AppModule" depends on the "dataModule", "dataManipulationModuleByService", and

"dataManipulationModuleByProvider" modules.

We have have 3 methods to add objects to an Angular module, namely factory, service, and provider.

The "appData" object is added to the "dataModule" by the "dataModule.factory()" method. The function

parameter passed to the "dataModule.factory()" method needs to return an object. The Angular DI

mechanism will get this object by calling this function and associate it with the module;

The "appDataManipulatorByService" object is added to the "dataManipulationModuleByService" by the

"dataManipulationModuleByService.service()" method. The function parameter passed to the

"dataManipulationModuleByService.service()" needs to be a Javascript constructor function. The Angular

DI mechanism will use this constructor function to create an object and associate it with the module;

The "appDataManipulatorByProvider" object is added to the "dataManipulationModuleByProvider" by the

"dataManipulationModuleByProvider.provider()" method. The function parameter passed to the

"dataManipulationModuleByProvider.provider()" method needs to be a constructor function. This

constructor function needs to add the "$get" method that returns an object. The Angular DI mechanism

will use the "$get" method to get the object that will be associated to the module.

When adding objects to the modules, we can inject objects already in the module or in other modules. The DI

mechanism will inject these objects to the "factory()", "service()", and "$get()" methods.

AngularJS Get Started and Miscellaneous - CodeProject http://www.codeproject.com/Articles/1022023/AngularJS-Get-Started-and-Miscellaneous?disp...

9 of 34 31/08/2015 15:07

To use objects in other modules, the current module needs to declare the other modules as

dependencies;

With standard Angular syntax, we need to use "['$scope', 'appData', 'appDataManipulatorByService',

'appDataManipulatorByProvider', function ($scope, data, sManipulator, pManipulator)()" to inject objects.

The "$scope", "appData", "appDataManipulatorByService", and "appDataManipulatorByProvider" are the

names of the objects. They will be injected in the order that is declared.

In this example, the "divAutomaticInitialization" is automatically bootstrapped, and the "divManuBootstrap-

angular" is manually bootstrapped. In the "divAutomaticInitialization", "MyController" is bound 3 times to two

different "DIV" elements. When we click the buttons, we should notice that the texts of the top two sections are

always synchronized regardless if we click on the "Add hello..." or the "Decrease hello..." buttons. But the text in

the last section changes by itself.

When a controller is bound to an HTML element, an independent "$scope" object is created by Angular,

the "$scope" object belongs to the binding;

The reason why the texts in the top two sections are synchronized is because the objects injected by

Angular DI are singletons. You may notice that the "appData" object from the "dataModule" is injected to

the "MyController". Although each binding of the controller creates its own "$scope", but the same

"appData" object is injected for each binding;

The scope of the singletons is an Angular bootstrap. The "divManuBootstrap-angular" is independently

bootstrapped, so Angular created another "appData" in its own bootstrap scope.

You can get more information about the scope of the Angular DI by looking at the Angular injector.

AngularJS Get Started and Miscellaneous - CodeProject http://www.codeproject.com/Articles/1022023/AngularJS-Get-Started-and-Miscellaneous?disp...

10 of 34 31/08/2015 15:07

3.basic-two-way-binding.html

This example is intended to demonstrate Angular's two way binding capability.

<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Angular Basic example</title><link rel="stylesheet" type="text/css" href="styles/app.css"> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.min.js"></script> <script type="text/javascript">

var module = angular.module('AppModule', []); module.controller('myController', ['$scope', function($scope) {

var defaultScore = {id: '', name: 'Please select ..'}; $scope.score = defaultScore; $scope.scoreOptions = [ defaultScore, {id: '80+', name: '80 and above'}, {id: '60+', name: '60 - 79'}, {id: '60-', name: 'Below 60'} ]; $scope.acceptance = function() {

var score = $scope.score.id;

if (! score)return 'Please select a score';

else if (score === '80+') return 'You are accepted to the school!';

else if (score === '60+')return 'You are in the waiting list';

elsereturn 'You are rejected';

}; }]); </script></head><body><div ng-app="AppModule" ng-strict-di>

AngularJS Get Started and Miscellaneous - CodeProject http://www.codeproject.com/Articles/1022023/AngularJS-Get-Started-and-Miscellaneous?disp...

11 of 34 31/08/2015 15:07

<div ng-controller="myController"><select ng-options="option.name for option in scoreOptions track by option.id"

ng-model="score"></select><span>{{acceptance()}}</span>

</div></div><br><div><a href="index.html">Back...</a></div></body></html>

This is a simple example that we have only a single dropdown box and a text label "<span>";

The user's choice of the dropdown box is bound to the "$scope.score" from the UI to the data model;

If the data model is changed, the "$scope.acceptance()" function is called to calculate the acceptance

status based on the given score. The acceptance status is then automatically shown in the text label

through the Angular binding.

In a real life application, we can well use an Ajax call to the server to do some more complex calculations

based on the number of applicants, and the numbers of the available slots, etc. But in this simple

example, I simply hard-coded the acceptance logic.

If we make changes to the selected values in the dropdown box, the acceptance status is automatically updated

and shown on the UI. Remember that we did not write any code to check the selected value in the dropdown

box and we did not write any code to update the text in the label. All the magic is done by the power of

Angular.

AngularJS Get Started and Miscellaneous - CodeProject http://www.codeproject.com/Articles/1022023/AngularJS-Get-Started-and-Miscellaneous?disp...

12 of 34 31/08/2015 15:07

4.basic-big-power-big-responsibility.html

This example is to extend the "3.basic-two-way-binding.html" to add some business meaning to see how

Angular performs.

The score is the primary acceptance criterion;

The other entries are just for information purpose;

If the score makes the student into the waiting list, the statement can help the school to make decisions.

The business logic in this example should make sense in most of the modern world, because race, gender, and

body type really should not matter when accepting a student to the school. I know that in the United States,

race and gender do matter in most of the cases, particularly to the best known schools like Harvard University.

But to be consistent to the "all men/women are created equal" principle, and to be consistent to Martin Luther

King's dreams, let me just use this simple business logic anyway.

AngularJS Get Started and Miscellaneous - CodeProject http://www.codeproject.com/Articles/1022023/AngularJS-Get-Started-and-Miscellaneous?disp...

13 of 34 31/08/2015 15:07

<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Angular Basic example</title><link rel="stylesheet" type="text/css" href="styles/app.css"> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.min.js"></script> <script type="text/javascript">

var module = angular.module('AppModule', []); module.controller('myController', ['$scope', function($scope) {

var defaultScore = {id: '', name: 'Please select ..'}; $scope.score = defaultScore; $scope.scoreOptions = [ defaultScore, {id: '80+', name: '80 and above'}, {id: '60+', name: '60 - 79'}, {id: '60-', name: 'Below 60'} ]; $scope.acceptance = function() {

var score = $scope.score.id; console.log('This can be an ajax call ...');

if (! score)return 'Please select a score';

else if (score === '80+') return 'You are accepted to the school!';

else if (score === '60+')return 'You are in the waiting list';

elsereturn 'You are rejected';

};

// Add more data to the applicationvar additionalInfo = {};

$scope.additionalInfo = additionalInfo; additionalInfo.race = null; additionalInfo.gender = null; additionalInfo.bodyType = null; additionalInfo.statementOfPurpose = null; }]);

AngularJS Get Started and Miscellaneous - CodeProject http://www.codeproject.com/Articles/1022023/AngularJS-Get-Started-and-Miscellaneous?disp...

14 of 34 31/08/2015 15:07

</script></head><body><div ng-app="AppModule" ng-strict-di>

<div ng-controller="myController" id="biggerapp"><div>

<select ng-options="option.name for option in scoreOptions track by option.id"ng-model="score"></select>

<span>&nbsp;{{acceptance()}}</span></div><div><span class="label">Race</span>

<input class="textinput" type="text" ng-model="additionalInfo.race" /></div><div><span class="label">Gender</span>

<input class="textinput" type="text" ng-model="additionalInfo.gender" /></div><div><span class="label">Body Type</span>

<input class="textinput" type="text" ng-model="additionalInfo.bodyType" /></div><div><span class="label">Statement</span>

<textarea class="textinput" ng-model="additionalInfo.statementOfPurpose"></textarea></div>

</div></div><br><div><a href="index.html">Back...</a></div></body></html>

If you load the example in your web page, you should notice that it works very well. When you select a score,

your acceptance status is shown to you right away. Now let us open the firebug and take a look at the Javascript

console.

AngularJS Get Started and Miscellaneous - CodeProject http://www.codeproject.com/Articles/1022023/AngularJS-Get-Started-and-Miscellaneous?disp...

15 of 34 31/08/2015 15:07

You will immediately see that the "$scope.acceptance()" function is called thousands of times. Remember

that this example is just a simple example. In really application, we will make an Ajax call to the server to

check the number of applicants and the number of available slots to make the acceptance decisions, so

each call is in fact an Ajax call;

The Ajax call is made whenever you perform any action on the UI, when you type in your race, type in

your statement. If you want to increase your chance of acceptance and write a long statement, the Ajax

call is made for your every keystroke. For each of your keystroke, the "$scope.acceptance()" is called at

least twice. your can easily let the application to make thousands of useless duplicate trips to the web

server, and most likely the database server too;

We all know that President Obama's web site went dead because people went there to send health

insurance applications. I read from the news that one keystroke on his web site will issue some Ajax calls

to his web server, so the server quickly went down. I am not sure if they used Angular to build the web

site, although I can easily find it out using firebug or other web development tools.

The reason of this virtually "Denial-of-service attack" type of behavior is due to the fact that Angular can provide

us powerful bindings, but it does not know our business logic. It does not know the fact that in the modern

AngularJS Get Started and Miscellaneous - CodeProject http://www.codeproject.com/Articles/1022023/AngularJS-Get-Started-and-Miscellaneous?disp...

16 of 34 31/08/2015 15:07

world, we strongly believe in "all men/women are created equal". The race, gender, and body type has

absolutely nothing to do with the acceptance. Without the knowledge of the business logic, angular took a

simple approach to be powerful, it calls the "$scope.acceptance()" function at least twice whenever we make a

single keystroke or possibly just a mouse leaving the text boxes. If you want to know why angular calls the

"$scope.acceptance()" at least twice but not once for every keystroke, you can check out the Angular digest

loop.

Big power should come with big responsibilities;

I am not trying to say that Angular encourages useless "Denial-of-service attack" type Ajax calls to

shut-down your own web servers and the database servers, but if we do not use Angular right, it is very

likely;

In the normal QA process, this problem may not be easily detectable since the QA server is normally

lightly loaded. If the QA personals do not keep the firebugs open, the problem can be very well go to the

production, where your production servers will get into the similar situation as President Obama's

servers.

5.basic-the-watcher.html

This example is intended to address the problem that we see in the "4.basic-big-power-big-responsibility.html".

<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Angular Basic example</title><link rel="stylesheet" type="text/css" href="styles/app.css"> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.min.js"></script> <script type="text/javascript">

var module = angular.module('AppModule', []); module.controller('myController', ['$scope', function($scope) {

var defaultScore = {id: '', name: 'Please select ..'}; $scope.score = defaultScore; $scope.scoreOptions = [ defaultScore, {id: '80+', name: '80 and above'}, {id: '60+', name: '60 - 79'},

AngularJS Get Started and Miscellaneous - CodeProject http://www.codeproject.com/Articles/1022023/AngularJS-Get-Started-and-Miscellaneous?disp...

17 of 34 31/08/2015 15:07

{id: '60-', name: 'Below 60'} ];

var defaultAcceptance = 'Please select a score'; $scope.acceptance = defaultAcceptance; $scope.$watch('score', function() {

var score = $scope.score.id;

if (score == '') { $scope.acceptance = defaultAcceptance;

return; } console.log('This can be an ajax call ...');

if (score === '80+') $scope.acceptance = 'You are accepted to the school!';

else if (score === '60+') $scope.acceptance = 'You are in the waiting list';

else $scope.acceptance = 'You are rejected'; });

// Add more data to the applicationvar additionalInfo = {};

$scope.additionalInfo = additionalInfo; additionalInfo.race = null; additionalInfo.gender = null; additionalInfo.bodyType = null; additionalInfo.statementOfPurpose = null; }]); </script></head><body><div ng-app="AppModule" ng-strict-di>

<div ng-controller="myController" id="biggerapp"><div>

<select ng-options="option.name for option in scoreOptions track by option.id"ng-model="score"></select>

<span>&nbsp;{{acceptance}}</span></div><div><span class="label">Race</span>

<input class="textinput" type="text" ng-model="additionalInfo.race" />

AngularJS Get Started and Miscellaneous - CodeProject http://www.codeproject.com/Articles/1022023/AngularJS-Get-Started-and-Miscellaneous?disp...

18 of 34 31/08/2015 15:07

</div><div><span class="label">Gender</span>

<input class="textinput" type="text" ng-model="additionalInfo.gender" /></div><div><span class="label">Body Type</span>

<input class="textinput" type="text" ng-model="additionalInfo.bodyType" /></div><div><span class="label">Statement</span>

<textarea class="textinput" ng-model="additionalInfo.statementOfPurpose"></textarea></div>

</div></div><br><div><a href="index.html">Back...</a></div></body></html>

This example is virtually the same as the "4.basic-big-power-big-responsibility.html".

Instead of using a function, it added a variable "$scope.acceptance" to bind it to the UI to report the

acceptance status;

A watcher is add to the "$scope.score". When the score selection changes, the watcher function will fire to

re-calculate the acceptance status.

If you run this example and set up your firebug, you will notice that the watcher function is only called when the

score changes.

If Angular is not used properly, it can be very error prone, but if you follow the best practices, it can

perform normally;

The fundamental of the best practice is that it is still the programmer's responsibility to tell when he/she

wants the program to do something and not to do something. Regardless how powerful the framework is,

there is no way to remove this duty from the programmers. Over these many years, the programming

environment has changed significantly. But what has not been changed is the definition of a computer

programming, which is "algorithm and data structure". Programmers still need to know the fundamentals.

There is no way to remove this duty from the programmers by simply using a powerful framework,

because any power comes with a cost and a responsibility.

6.basic-filter.html

This example is to demonstrate Angular's filter capability.

AngularJS Get Started and Miscellaneous - CodeProject http://www.codeproject.com/Articles/1022023/AngularJS-Get-Started-and-Miscellaneous?disp...

19 of 34 31/08/2015 15:07

<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Angular Basic example</title><link rel="stylesheet" type="text/css" href="styles/app.css"> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.min.js"></script> <script type="text/javascript">

var module = angular.module('AppModule', []); module.controller('myController', ['$scope', function($scope) {

var defaultScore = {id: '', name: 'Please select ..'}; $scope.score = defaultScore; $scope.scoreOptions = [ defaultScore, {id: '80+', name: '80 and above'}, {id: '60+', name: '60 - 79'}, {id: '60-', name: 'Below 60'} ];

var additionalInfo = {}; $scope.additionalInfo = additionalInfo; additionalInfo.statementOfPurpose = null; }]) module.filter('checkStatus', function() {

return function(score) {var scoreId = score.id;

console.log('This can be an ajax call ...');

if (! scoreId)return 'Please select a score';

else if (scoreId === '80+') return 'You are accepted to the school!';

else if (scoreId === '60+')return 'You are in the waiting list';

elsereturn 'You are rejected';

} }); </script></head><body>

AngularJS Get Started and Miscellaneous - CodeProject http://www.codeproject.com/Articles/1022023/AngularJS-Get-Started-and-Miscellaneous?disp...

20 of 34 31/08/2015 15:07

<div ng-app="AppModule" ng-strict-di><div ng-controller="myController" id="biggerapp">

<div><select ng-options="option.name for option in scoreOptions track by option.id"

ng-model="score"></select><span>{{score|checkStatus}}</span>

</div><div><span class="label">Statement</span>

<textarea class="textinput" ng-model="additionalInfo.statementOfPurpose"></textarea></div>

</div></div><br><div><a href="index.html">Back...</a></div></body></html>

We have seen from the example "4.basic-big-power-big-responsibility.html" that sometimes Angular can create

undesirable situations. Now let us see how filter works.

This example created a filter function called "checkStatus";

We can simply bind it to the UI with the "{{score|checkStatus}}" syntax to report the acceptance status.

We can then load the example page into the browser and select a score. We can also type in some statement.

Everything looks normal and functional. We may hope that the Ajax calls will not fire for every key stroke,

AngularJS Get Started and Miscellaneous - CodeProject http://www.codeproject.com/Articles/1022023/AngularJS-Get-Started-and-Miscellaneous?disp...

21 of 34 31/08/2015 15:07

because the "{{score|checkStatus}}" syntax explicitly tells Angular to filer the "score" only. Let us now look at the

firebug console.

But unfortunately, we again got thousands of Ajax calls, at least two Ajax calls for each keystroke. This example

shows us that we will need to use Angular filters with caution. It can fire when you do not intend it to fire.

7.basic-oops-what-is-going-on.html

This example shows an unstable situation if we do not use Angular properly. This situation can occur in any

environment, not just Angular. But now let us see how it can happen in Angular.

<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Angular Basic example</title>

AngularJS Get Started and Miscellaneous - CodeProject http://www.codeproject.com/Articles/1022023/AngularJS-Get-Started-and-Miscellaneous?disp...

22 of 34 31/08/2015 15:07

<link rel="stylesheet" type="text/css" href="styles/app.css"> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.min.js"></script> <script type="text/javascript">

var module = angular.module('AppModule', []); module.controller('myController', ['$scope', function($scope) { $scope.first = 0; $scope.second = 0; $scope.increaseFirst = function() { $scope.first++; } $scope.$watch('first', function() {

if ($scope.first == 0) return; $scope.second--; }); $scope.$watch('second', function() {

if ($scope.second == 0) return; $scope.first++; }) }]); </script></head><body><div ng-app="AppModule" ng-strict-di>

<div ng-controller="myController"><div>First: {{first}}</div><div>Second: {{first}}</div><div><button type="button" ng-click="increaseFirst()">Increase First...</button></div>

</div></div><br><div><a href="index.html">Back...</a></div></body></html>

We added two variables "first" and "second" to the "$scope";

A watcher function is used to watch the change of the "first" variable. When it changes, we decrease the

"second" variable by 1;

A watcher function is used to watch the change of the "second" variable. When it changes, we increase

the "first" variable by 1;

AngularJS Get Started and Miscellaneous - CodeProject http://www.codeproject.com/Articles/1022023/AngularJS-Get-Started-and-Miscellaneous?disp...

23 of 34 31/08/2015 15:07

The "$scope.increaseFirst()" function is bound to the click event of the button to increase the "first"

variable by 1.

Load the example into the web browser and click on the "Increase First..." button, you can see that the numbers

stopped at 12. Now let us take a look at the firebug console.

AngularJS Get Started and Miscellaneous - CodeProject http://www.codeproject.com/Articles/1022023/AngularJS-Get-Started-and-Miscellaneous?disp...

24 of 34 31/08/2015 15:07

Any experienced programmer should have noticed that we had an infinite loop which can happen in any

environment, not just in Angular;

In Angular, because the digest loop has to run at least twice for a single change of a variable on the

"$scope" to achieve the kind of power that Angular provides us, we need to be very careful to modify the

values of the data in an Angular controller, particularly when you have a larger problem. When the data

model has many data variables, the infinite loop condition will not be as easily identify as this simple

example when we have only two variables.

8.basic-a-bare-javascript-solution.html

AngularJS Get Started and Miscellaneous - CodeProject http://www.codeproject.com/Articles/1022023/AngularJS-Get-Started-and-Miscellaneous?disp...

25 of 34 31/08/2015 15:07

This is an example to achieve the same as the "4.basic-big-power-big-responsibility.html". It does not use

Angular, it does not even use jQuery. I wanted to figure out how difficult life can be without Angular. I almost

wanted to skip this example, because I really did not have time to full test it. But I finally put it here as a

reference. If you want to use any code in this example, please make sure to test it yourself. In order to achieve

something similar to the two-way binding, I created a Javascript file "simple-mapper.js".

var simplemapper = function(model) { var data = model.data; var elementMapping = model.elementMapping;

return { serialize: function(item) { var mapping = elementMapping[item]; var e = document.getElementById(mapping.element); data[item] = (mapping.type == 'value')? e.value: e.innerHTML; }, deserialize: function(item) { var mapping = elementMapping[item]; var e = document.getElementById(mapping.element);

if (mapping.type == 'value') e.value = data[item];

else e.innerHTML = data[item]; }, serializeMultiple: function(itemArray) { var len = itemArray.length

for(var i = 0; i < len; i++){ var item = itemArray[i]; var mapping = elementMapping[item]; var e = document.getElementById(mapping.element); data[item] = (mapping.type == 'value')? e.value: e.innerHTML; } }, deserializeMultiple: function(itemArray) { var len = itemArray.length

for(var i = 0; i < len; i++){ var item = itemArray[i]; var mapping = elementMapping[item]; var e = document.getElementById(mapping.element);

if (mapping.type == 'value') e.value = data[item];

else e.innerHTML = data[item]; }

AngularJS Get Started and Miscellaneous - CodeProject http://www.codeproject.com/Articles/1022023/AngularJS-Get-Started-and-Miscellaneous?disp...

26 of 34 31/08/2015 15:07

}, serializeAll: function() {

for(var item in elementMapping){this.serialize(item)

} }, deserializeAll: function() {

for(var item in elementMapping){this.deserialize(item)

} }, getUpdatedDataItem: function(item) {

this.serialize(item);return data[item];

}, getUpdatedData: function() {

this.serializeAll();return data;

} };};

The "simplemapper()" function is to create the two way mapping utility object, it takes your data model;

The data model has two objects, the "model.data" object is the data part, and the

"model.elementMapping" object tells the mapping object how to map the data to the UI elements;

The "serialize(item)" method updates the data from the UI element for the particular "item", while the

"deserialize(item)" updates the UI element from the data for the particular "item";

I create a couple of "serialize()" and "deserialize()" methods for different granularities.

<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Angular Basic example</title><link rel="stylesheet" type="text/css" href="styles/app.css"> <script src="scripts/simple-mapper.js"></script> <script type="text/javascript">

var appModel = function() {return {

data: { score: '', acceptance: 'Please select a score',

AngularJS Get Started and Miscellaneous - CodeProject http://www.codeproject.com/Articles/1022023/AngularJS-Get-Started-and-Miscellaneous?disp...

27 of 34 31/08/2015 15:07

race: '', gender: '', bodyType: '', statementOfPurpose: '' }, elementMapping: { score: {element: 'selScores', type: 'value'}, acceptance: {element: 'spanAcceptance', type: 'html'}, race: {element: 'txtRace', type: 'value'}, gender: {element: 'txtGender', type: 'value'}, bodyType: {element: 'txtBodyType', type: 'value'}, statementOfPurpose: {element: 'txtStatementOfPurpose', type: 'value'} } }; }();

var controller = function(model) {var sm = simplemapper(model);var data = model.data;

return {

mapper: sm, checkAcceptance: function() {

var score = sm.getUpdatedDataItem('score'); console.log('This can be an ajax call ...');

if (score == '') data.acceptance = 'Please select a score';

else if (score === '80+') data.acceptance = 'You are accepted to the school!';

else if (score === '60+') data.acceptance = 'You are in the waiting list';

else data.acceptance = 'You are rejected'; sm.deserialize('acceptance'); }, checkSerialization: function() { console.log(sm.getUpdatedData()); } } }(appModel); window.onload = function() { controller.mapper.deserializeAll(); }

AngularJS Get Started and Miscellaneous - CodeProject http://www.codeproject.com/Articles/1022023/AngularJS-Get-Started-and-Miscellaneous?disp...

28 of 34 31/08/2015 15:07

</script></head><body><div>

<div id="biggerapp"><div>

<select id="selScores" onchange="return controller.checkAcceptance()"><option value=''>Please select ..</option><option value='80+'>80 and above</option><option value='60+'>60 - 79</option><option value='60-'>Below 60</option>

</select>&nbsp;<span id="spanAcceptance"></span></div><div><span class="label">Race</span>

<input class="textinput" type="text" id="txtRace" /></div><div><span class="label">Gender</span>

<input class="textinput" type="text" id="txtGender" /></div><div><span class="label">Body Type</span>

<input class="textinput" type="text" id="txtBodyType" /></div><div><span class="label">Statement</span>

<textarea class="textinput" id="txtStatementOfPurpose"></textarea></div><div>

<button type="button" onclick="return controller.checkSerialization()"> Check serialization</button>

</div></div>

</div><br><div><a href="index.html">Back...</a></div></body></html>

The "appModel" object is the application's data model. The "appModel.data" is the application's data, the

"appModel.elementMapping" tells the mapper object how to map the data to the UI elements;

The "element" entry for the "elementMapping" is the "id" of the HTML element on the UI, and the "type"

entry tells if the data is the value of the HTML element or the innerHTML of the HTML element;

The "controller" object is created based on the "appModel" object. It has its own "simplemapper" built

from the "simple-mapper.js", it also exposes the "checkAcceptance()" and "checkSerialization()" methods;

The "appModel" and the UI elements are bound together though the "controller" in the "window.onload"

event.

AngularJS Get Started and Miscellaneous - CodeProject http://www.codeproject.com/Articles/1022023/AngularJS-Get-Started-and-Miscellaneous?disp...

29 of 34 31/08/2015 15:07

You may notice that we actually did not write too much more code in "8.basic-a-bare-javascript-

solution.html" to achieve the same functionality compared with the "4.basic-big-power-

big-responsibility.html".

If you click on the "Check serialization" button and take a look at the Javascript console in your firebug, you

should find that all the data you put into the UI is serialized to your data model. The following is from firefox

and I re-typed the text as above when I tried to show them in firebug, I made a typo for "1/1 W 1/1 B ....", I hope

you do not mind. You can run the example by yourself anyway.

AngularJS Get Started and Miscellaneous - CodeProject http://www.codeproject.com/Articles/1022023/AngularJS-Get-Started-and-Miscellaneous?disp...

30 of 34 31/08/2015 15:07

You can also check if there are any unintentional Ajax calls. Of course no, because the program has absolute

control on when the Ajax call should be made.

Points of interests

This is a study note on Angular. I realized that Angular is a larger topic than I initially thought of;

I did not intend to make it so long, but it ended up so long and I apologize for it being so long;

Angular is a nice tool/framework that helped me to solve the two problems that I mentioned at the

beginning, name collision in Javascript and data model binding to HTML elements;

Angular is a powerful tool/framework. To use it well, you need to strictly follow the best practices and you

may also need to keep finding out more best practices from your own mistakes;

It is a good idea to keep your firebug or other development tools open, and it is a good idea to print out

some debug information in your Javascript console to watch any undesirable behaviors and correct them

as quickly as possible. Some problems may not be easily detectable by the QA people;

I hope you like my postings and I hope this study note can help you one way or the other.

History

First Revision - 8/30/2015

License

AngularJS Get Started and Miscellaneous - CodeProject http://www.codeproject.com/Articles/1022023/AngularJS-Get-Started-and-Miscellaneous?disp...

31 of 34 31/08/2015 15:07

This article, along with any associated source code and files, is licensed under The Code Project Open License

(CPOL)

Share

About the Author

You may also be interested in...

Node.js Get Started and

Miscellaneous

Open Source in the Enterprise:

What Every Development Team

Should Know Before Starting Their

Next App

Dr. Song LiUnited States

I have been working in the IT industry for some time. It is still exciting and I

am still learning. I am a happy and honest person, and I want to be your

friend.

AngularJS Get Started and Miscellaneous - CodeProject http://www.codeproject.com/Articles/1022023/AngularJS-Get-Started-and-Miscellaneous?disp...

32 of 34 31/08/2015 15:07

Permalink | Advertise | Privacy | Terms of Use | Mobile

Web02 | 2.8.150819.1 | Last Updated 30 Aug 2015Selecione o idioma ▼

Article Copyright 2015 by Dr. Song Li

Everything else Copyright © CodeProject, 1999-2015

Part1: Introduction to AngularJS Beyond RDBMS: A Guide To NoSQL

Databases

Validation in AngularJS Four App Deployment Disasters

Every Business Should Know About

Comments and Discussions

0 messages have been posted for this article Visit http://www.codeproject.com/Articles/1022023/AngularJS-

Get-Started-and-Miscellaneous to post and view comments on this article, or click here to get a print view with

messages.

AngularJS Get Started and Miscellaneous - CodeProject http://www.codeproject.com/Articles/1022023/AngularJS-Get-Started-and-Miscellaneous?disp...

33 of 34 31/08/2015 15:07

AngularJS Get Started and Miscellaneous - CodeProject http://www.codeproject.com/Articles/1022023/AngularJS-Get-Started-and-Miscellaneous?disp...

34 of 34 31/08/2015 15:07