Vous êtes sur la page 1sur 34

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

Articles » Languages » Java » General

AngularJS Get Started and Miscellaneous


Dr. Song Li, 30 Aug 2015 CPOL 1.7K 22 8
5.00 (1 vote)

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;

1 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...

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

2 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...

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">

3 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...

<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>

4 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...

<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)".

5 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...

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

6 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...

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 modules
var 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;
};
}]);

7 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...

// 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>

8 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...

</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.

9 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...

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.

10 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...

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';
else
return 'You are rejected';
};
}]);

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

11 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...

<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.

12 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...

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.

13 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...

<!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';
else
return 'You are rejected';
};

// Add more data to the application


var additionalInfo = {};
$scope.additionalInfo = additionalInfo;

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

14 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...

</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.

15 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...

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

16 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...

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'},

17 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...

{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 application


var 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" />

18 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...

</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.

19 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...

<!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';
else
return 'You are rejected';
}
});

</script>
</head>
<body>

20 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...

<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,

21 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...

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>

22 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...

<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;

23 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...

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.

24 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...

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

25 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...

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];
}

26 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...

},
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',

27 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...

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();
}

28 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...

</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.

29 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...

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.

30 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...

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

31 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...

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

Share

About the Author


Dr. Song Li
United 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.

You may also be interested in...


Node.js Get Started and Open Source in the Enterprise:
Miscellaneous What Every Development Team
Should Know Before Starting Their
Next App

32 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...

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.

Permalink | Advertise | Privacy | Terms of Use | Mobile Article Copyright 2015 by Dr. Song Li
Selecione o idioma ▼
Web02 | 2.8.150819.1 | Last Updated 30 Aug 2015 Everything else Copyright © CodeProject, 1999-2015

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

Vous aimerez peut-être aussi