Sei sulla pagina 1di 21

Using the AngularJS Package for Sublime Text

AngularJS Sublime Text Package features include:

Code completion of core AngularJS directives (ng-model, ng-repeat, etc.)


Code completion for key AngularJS objects and components such as directive
Support for custom directive code completion
Enhanced functionality within AngularJS HTML templates defined in a page
Ability to customize the attributes, element directives, etc.

AngularJS How to Code Quickly with Sublime Text Editor


Do the following and enjoy the Angular ride much more than ever:

Download and install Sublime Text Editor from http://www.sublimetext.com/.


Download Angular Sublime package (zip file) developed by Angular-UI team from this
page:https://github.com/angular-ui/AngularJS-sublime-package. This page consists of greater details on
further customizing the Sublime for AngularJS.
Unzip and name the root package (angularjs-sublime-packager-master) as AngularJS. Make sure you have
all the files just within this package.
Copy AngularJS folder.
Open Sublime Text Editor and paste AngularJS folder by opening Preferences > Browse Packages
Paste some of the following configuration (JSON format) by opening the Preferences > Settings User.
The file would look like following:
// Settings in here override those in "Default/Preferences.sublime-settings", and
// are overridden in turn by file type specific settings.
{
"auto_complete_selector": "source - comment, meta.tag - punctuation.definition.tag.begin",
"auto_complete_triggers":
[
{
"characters": "ng-controller=\"*",
"selector": "punctuation.definition.string"
}
]
}
Close Sublime and open it again. And, try your AngularJS hello world program. You could check the
preferences related with AngularJS and customize appropriately as shown in following screenshot.

Reference:
http://vitalflux.com/angularjs-code-quickly-sublime-text-editor
http://java.dzone.com/articles/angularjs-how-code-quickly

1|Page

Basics
AngularJS is a client-side web application framework that reimagines HTML.
Let that sink in. If you are an experienced web developer, you have probably already compared Angular to familiar
JavaScript frameworks and libraries, such as jQuery, Knockout, Backbone,Ember, and possibly even React.
Similarly, if you know something about GUI programming, you may have tried to relate Angular to Model View
Controller (MVC) or Model View ViewModel (MVVM). These impulses are natural, but they can cloud your
understanding of Angular. For this chapter only, I would ask you to let go of thinking of Angular as a JavaScript
framework. Hold off for a moment on trying to understand how it works under the hood. Take Angular at face value.
Experience it just as a powerful set of extensions to HTML.
We'll start with three fundamental Angular constructs: expressions, directives, and scopes. However, before we get
into the examples, let's quickly review how to get Angular working in a web page. (Or, skip ahead to start the section
on expressions.)

Set up
Where do you get Angular? While you can download it from the official site, loading Angular into your page
from Google Hosted Libraries (a CDN) is both convenient and likely to perform well. The live examples in this page
do so by including the script tag shown below within the head element.
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.js"></script>
After including the Angular library file, you need to let Angular know which part of the HTML document it should
manage. Remember that Angular is HTML-oriented rather than JavaScript-oriented. Rather than writing some
JavaScript to load it, we instead add some non-standard HTML that Angular will recognize. This is a special ngapp attribute that we can add to any element in the DOM. For the examples in this chapter, we will place it on
the body element, as shown below. By choosing to put it on the body or html element, we give our Angular
application control over our entire page. You can pick a narrower scope if you like, which allows you to use another
framework alongside Angular, or even load additional Angular applications. This makes sense for a more traditional,
document-oriented web site in which client-side code is contained within isolated widgets, rather than a singlepage application (SPA).
<body ng-app>
<!-- Other examples in this chapter will be inserted here. -->
</body>
With this magic attribute, we now have Angular working in our page. Now then, what can we do with it?

Expressions
Be warned: If you have been trained in the doctrine of unobtrusive JavaScript, the following examples may set off
alarm bells, as Angular's first order of business is to allow you to mix JavaScript-like expressions into your HTML.
Angular expressions can be almost any simple, valid JavaScript, although flow control structures like loops and
some other things are not allowed. Please suspend judgement as we explore the boundaries of what is permitted
(but not necessarily in good taste) through some old-fashioned experimentation.
Let's start by adding two numbers. Like all of the code in this book, the listing below is a live editor that lets you
modify the example. You may change any part of it. The output is rendered within aniframe sandbox and will be
instantly updated.
<p>The number {{3 + 4}}.</p>
Go ahead, replace 3 + 4 in the live example above with a different math expression. See if you can find something
that Angular won't or can't handle. (When Angular fails to process an expression, it either outputs the original string,
or in the case of some errors, nothing at all.)
2|Page

The double curly brackets are template delimiters. If you are familiar with Mustache or perhapsHandlebars, then
you have seen double curly brackets used this way before. One way to think of Angular is just as a really
sophisticated templating library. It treats everything within the element you marked with ng-app as a template that
is compiled when your page loads, and re-rendered whenever there are changes to data. (Don't worry if you are
unfamiliar with templating; we'll cover the basics of it later.)
How about testing the equality of two values? Sure, we can do that too.
<p>Are strings and numbers equal? {{'2' == 2}}</p>
The result is correct for JavaScript. If you're surprised by it, quickly review JavaScript comparison operators, then
change == to === in the example above. (Strict comparisons are better, right?)
Here is an example that concatenates strings and also demonstrates that we have access to standard library
functions such as String's toUpperCase instance method.
<p>{{"Angular" + "js".toUpperCase()}}</p>
Are you getting the feeling that you can do whatever you want inside expressions? Not so fast, partner.
<!-- Invalid code! This function call is not permitted in an expression. --> <p>{{alert("Hello world")}}</p>
You definitely can't use alert. Nor can you access most of JavaScript's global objects, such Math,Number, Date,
and so on.
Try replacing alert("Hello world") in the example above with parseInt("1"), Date.now(),Number.NaN,
and Math.random(). If no output is shown, Angular has refused to parse the expression.
Although Angular limits what you can do in expressions, I suspect you will exhaust your tolerance for mixing code
and markup before you feel constrained by the framework. Let's probe the limits in any case. Do you think we can
assign variables?
<p>{{a = 1; a + a}}</p>
It works. But try adding the var keyword before the variable name. Do you get an error? If you see the raw expression
including the delimiters in the output, you have caused an error. Do not feel bad. Breaking things is a great way to
learn.
So is experimentation. I do not know if a variable assigned inside one set of delimiters can be used within another.
Why not try?
<p>{{a = 1}} remains {{a}}</p>
Yes, it works. What if you move the initialization of the variable to the second expression? Go ahead, try it. Does it
work? Can you guess a possible reason why?
Ok, expressions support assignment. What about the ternary operator?
<p>There {{count = 1; (count == 1 ? "is " : "are ") + count}} of them.</p>
Fortunately that works as well, since the ternary operator offers a concise syntax that can be really useful in
templates.
Now, what about the increment operator (++)? Can we use that?
<p>{{a = 1; ++a}}</p>
Apparently not. Still, what about a for loop? We'll avoid idiomatic use of var and the increment operator, since we've
already disqualified those.
<p>{{for (i = 0; i < 10; i = i + 1) {i}}}</p>

3|Page

The for loop is not executed. It produces a syntax error that you should be able to see in your browser's console.
But there is nothing invalid in the JavaScript in this statement. In the browser's console, paste the statement for (i
= 0; i < 10; i = i + 1) {i};. It should evaluate to 9. Go ahead, try it. So, we have hit a few boundaries: Angular
expressions are not JavaScript. Theexpression language does not support conditionals, loops, or throwing errors.
We have likely pushed things far enough with expressions. Personally, I am ok with some JavaScript in my markup
when it is concise and view related, so I appreciate the relatively permissive nature of Angular expressions. However,
any more than just a little JavaScript within a template rapidly becomes unsightly and confusing. Fortunately,
expressions merely play a supporting role in Angular. We should never feel the need to place too much code within
them.
The real key to Angular's mind-blowing productivity is the directive.

Directives
Directives are the heart and soul of Angular. I recommend that you start out by thinking of them simply as custom
HTML. Most of the time, directives appear in the form of attributes that can be used on normal, familiar elements.
The built-in directives that come pre-packaged with Angular generally start with an ng- prefix, which is a reference
to the ng in Angular. There are also countless third-party directives now available. There must be a directive for
that should be your standard reaction when you see verbose JavaScript within an Angular expression.
We have already used a directive. Do you remember it? To get Angular working in the live examples in this chapter,
we added ng-app to the page's body element. (Go back for a look.) In this case, we used the directive without
passing any arguments to it. When you pass arguments to a directive, you simply use ="", just as you would with
a normal HTML attribute. For example, we could pass in the name of application with ng-app="myApp". (The
application name is actually the name of a module, an important part of Angular's architecture that is covered in
the Modules chapter.)

ng-bind
Some directives accept and parse string expressions. (You can verify the parameters for a built-in directive by visiting
its API documentation.) For example, the ng-bind directive simply renders expressions, just like the double curly
brackets that we used in the previous section. This is what it looks like.
<p>The number <span ng-bind="3 + 4"></span>.</p>
While this simple usage results in exactly the same output as the first example above, there is an important
difference in the behavior of ng-bind: The content of the element to which you apply ng-bind is replaced when the
template is rendered. Therefore, the preferred technique is to use ng-bindbut to not put anything inside the element,
with the result that during the brief moment before Angular replaces your raw template, nothing is shown. This can
be advantageous. Depending on the user's environment and the size and behavior of your Angular application,
there can be actually be a delay that allows users to see the double curly bracket delimiters and expressions in your
uncompiled page content. Using ng-bind on empty elements avoids this.
At some point as your Angular application grows in size, you may want to address these flicker issues at a higher
level by hiding most or all of your content until Angular has loaded. This is easy to do with the ng-cloak directive.
See why there must be a directive for that is the right mindset?

ng-init
Remember how we initialized a variable in an expression, just to see if it would work? Well, you guessed it: There
is also a directive for that. With ng-init, you can initialize variables for use anywhere within the element to which
it is applied.
<div ng-init="sum = 3 + 2"> <p> {{sum + 1}} is more than <span ng-bind='sum - 1'></span> </p>
</div>
Using semicolons to delimit statements, you can initialize as many variables as you like.
<div ng-init="count = 7; units = 'days'; collection = 'week'"> <p> There are {{count}} {{units}} in a
{{collection}}. </p> </div>
4|Page

At some point, you may find it better to organize your variables as the properties of an object.
<div ng-init="time = {count: 12, units: 'months', collection: 'year'}"> <p> There are {{time.count}}
{{time.units}} in a {{time.collection}}. </p> </div>
Arrays are also useful.
<div ng-init="months = ['January','February','March','April']"> <p> {{months[3]}} follows {{months[2]}} in
{{months}}. </p> </div>
It is important to be careful about property names when coding Angular templates. You can probably spot the
errors in the template below by looking, but don't expect any help from Angular. It quietly tolerates all property
access errors, including nested properties on nonexistent parents and out-of-bounds array access.
<div ng-init="paragraph = {sentence: {words: ['first','second','third']}}"> <p> "{{typo.sentence.words[0]}}",
"{{paragraph.typo.words[1]}}", "{{paragraph.sentence.typo[2]}}", "{{paragraph.sentence.words[3]}}". </p>
</div>
My personal wish is that instead of being so tolerant, Angular had employed something like CoffeeScript's
wonderfully concise existential operator (?) to make these silent access failures an option rather than the rule.
Given Angular's permissiveness so far, do you think we are permitted to declare functions withinng-init? What
would you guess?
<div ng-init="count = function() { return 12; }"> <p> There are {{count()}} months in a year. </p> </div>
No, the function expression above is not allowed. While trying to process the argument to ng-init, Angular throws
a $parse:syntax error that you can see in the JavaScript console of your browser. The correct place to declare
functions for use in Angular expressions is within a controller, as we will learn in the
upcoming Controllers chapter. In fact, controllers are the proper place to prepare application data for the view.
The ng-init directive, while fun to play with in this chapter, is actually intended for aliasing variables as a way to
cope with variable shadowing, as we shall see in the Collections chapter.

ng-non-bindable
By the way, if you need to shield some part of your document from Angular's processing, adding ng-non-bindable to
an element will exclude its contents from compilation.
<p ng-non-bindable> {{2 * 2}} is the same as <span ng-bind='2 + 2'>?</span> </p>
Remove the ng-non-bindable directive from the example above to see what happens.

ng-show
It is time to explore something more than simply rendering expressions. For starters, how can we conditionally
display or hide an HTML element?
I can offer some advice from my own experience of how not to do this with Angular. The very first time I used
Angular, I needed to hide a form after the user successfully submitted it. Inside a controller that I had created to
handle the user action, I added a call to jQuery.hide(). It worked, of course, and if you are learning Angular within
the context of a fast-paced project, sometimes you need to be pragmatic. However, there must be a directive for
that would have served me well. Indeed there is. Two directives, in fact: ng-hide and ng-show.
We can demonstrate the use of both at the same time.
<p ng-init="authorized = true">
The secret code is
<span ng-show="authorized">0123</span>
<span ng-hide="authorized">not for you to see</span>
5|Page

</p>
Change true to false in the example to see what happens. Since Angular is always watching for changes, you can
toggle the value of a variable like authorized anywhere you have access to it, and the view will be updated for the
user.
At this point, it is probably time to go a bit more in depth about variables like authorized and understand what
they actually are.

Scopes
Scopes provide a single source of truth within your application. The idea is that no matter in how many places you
display some data in your view layer, you should only have to change it in one place (a scope property), and the
change should automatically propagate throughout the view.
Since this automatic rendering and re-rendering requires infrastructure, the most notable thing about the JavaScript
objects that you set on Angular scopes is how ordinary they appear. You may be familiar with the concept of plain
old domain model objects. The original is the Plain Old Java Object, or POJO. When the POJO idea was first
explained by Martin Fowler, he meant the basic, ordinary objects directly provided by the core language runtime,
as opposed to unwieldy domain model objects that inherit special capabilities from a framework superclass.
However, the term wasextended to mean objects that appear plain but which are transparently enhanced by a
framework with special runtime capabilities, typically persistence.
The objects attached to Angular scopes are JavaScript POJOs, since Angular applies sophisticated change detection
at runtime in order to propagate changes. When the Object.observe language feature makes it into mainstream
JavaScript, Angular may truly become a plain old JavaScriptframework.
We have already seen scope properties in this chapter. Remember the variables that we initialized inside expressions
and using ng-init in the examples above? These are are all scope properties. Remember when I asked you to add
the var keyword to an expression? Using var is prohibited because what I previously called variables (my apologies
for the deception) are in fact properties on a scope object that is automatically created for us behind the scenes.
The next chapter will cover scopes in greater depth. Right now let's get into some hands-on examples that
demonstrate how we use scope properties.

Two-way binding
So far, we have seen examples of one-way binding, in which scope data is dynamically updated in the view. Things
really get exciting when you use HTML controls to modify this data. Together with the view updates, this is referred
to as two-way binding.
For a primitive first example, we can use the ng-click directive to modify a boolean property.
<p ng-init="authorized = true">
The secret code is
<span ng-show="authorized">0123</span>
<span ng-hide="authorized">not for you to see</span>
<br>
<input type="button" value="toggle" ng-click="authorized = !authorized">
</p>
The argument to ng-click can be any expression. Although it is a versatile directive that is not limited to acting upon
scope properties, the inline code for flipping a boolean works well since it is so simple. But how do you bind more
sophisticated inputs and data types?

ng-model
6|Page

It seems like every introduction to Angular demonstrates data binding with a text input and a string property.
Finally, it's our turn.
<input type="text" ng-model="title">
is bound to
"<strong ng-bind="title"></strong>".
Type something in the box!
This example is the poster child for two-way binding. When we add the ng-model directive to the
HTML input element, Angular wraps the default HTML control in its own input directive.
What more can we do? Well, we can always use ng-init to provide an initial property value.
<input type="text" ng-init="title = 'Angular'" ng-model="title">
is bound to
"<strong ng-bind="title"></strong>".
Change it!
Let's try some other input types. Here is a checkbox.
<input type='checkbox' ng-init='optIn = true' ng-model='optIn'>
is bound to
<strong ng-bind="optIn"></strong>.
Change it!
The value bound to a checkbox can be a string rather than a boolean if you set the ng-true-valueand ng-falsevalue parameters.
<input type='checkbox' ng-init='feeling = "love it"' ng-model='feeling'
ng-true-value='"love it"' ng-false-value='"hate it"'>
is bound to
"<strong ng-bind="feeling"></strong>".
Change it!
Angular's select directive works as you might expect. Notice that it ignores the selected attribute on the
first option. Remove the ng-init directive and you will see that selected still has no effect.
<select ng-init='answer = "maybe"' ng-model='answer'>
<option value='yes' selected>Yes</option>
<option value='no'>No</option>
<option value='maybe'>Maybe</option>
</select>
is bound to
"<strong ng-bind="answer"></strong>".
Change it!
With just three options, the last example might work better as a group of radio buttons. No problem, let's change
it.
<div ng-init='answer = "maybe"'>
<input type='radio' ng-model='answer' value='yes'> Yes
<input type='radio' ng-model='answer' value='no'> No
<input type='radio' ng-model='answer' value='maybe'> Maybe
is bound to
"<strong ng-bind="answer"></strong>".
Change it!
</div>
You now have some real-world experience manipulating scope data using Angular directives. There are many
more built-in directives, and we will explore a number of them in the upcoming chapters.

7|Page

Conclusion
At the beginning of this chapter, I asked you not to think of Angular as a JavaScript framework, but rather as a set
of extensions to HTML. As Angular creator Miko Hevery recounts in this fascinating interview, Angular was
originally conceived as a radically more productive way for front-end developers to enhance web pages. The
JavaScript framework came later.
Central to Angular's original strategy is the premise that a declarative programming style is the best fit for rapid
GUI development. However, rather than asking developers to invest in a new domain-specific language (DSL) for
web development, as was attempted with MXML and XUL, Angular builds upon the widespread familiarity of
HTML.
So much for the vision. For the moment at least, Angular is virtually never used without custom JavaScript. Realworld Angular applications almost always make use of controllers, services, androuters, as well as
supporting modules, dependency injection, and Ajax infrastructure, all of which is covered in this book. However,
the productivity promise of Angular is still best realized when a web developer is able to work mainly in the
declarative space, with a degree of confidence that there must be a directive for that. Writing custom
directives to fill the gaps is one of the more challenging areas of Angular, which is why this chapter tries to start
your Angular journey with the end in mind. Now that you understand that the ultimate goal is productivityboosting extensions to HTML, rather than just writing JavaScript code within a framework, you are better
prepared to dive into the details.

8|Page

Controllers
In the previous chapter, Basics, I asked you to rein in your JavaScript horses while we explored Angular's original
value proposition, which is to provide the front-end developer with powerful extensions to HTML. Of course, the
Angular story doesn't end there, and customizing behavior via JavaScript is the norm for virtually every Angular
project. If you spent the first chapter wondering when we would get to some real coding, your patience will now be
rewarded. It's time to write JavaScript.
The most common way to augment an Angular view using JavaScript is with a controller. The easiest way to write
a controller is as a plain old constructor function. In order to understand exactly what is happening, let's start out
with a very simple controller. This is not even hello world. It does absolutely nothing.
This is our controller.
function EmptyController() {
};
Rendering the scope properties prepared by a controller requires the Angular library file. The fragment below will
be copied inside the head element of each rendered example.
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.js"></script>
In the HTML document, we must configure our Angular application to load the app module. In the previous
chapter, Basics, I showed how to add the ng-app directive to an element in order to tell Angular which part of your
document it should process. Look at the usage of ng-app in the example below. Can you pick out the new addition?
<body ng-app="app">
<!-- Other examples to be inserted here. -->
</body>
Controllers can be defined as constructor functions declared on the global scope, and that is the approach we will
use in this chapter. This simple form of controller was supported by default in Angular versions up to 1.3 to facilitate
developer onboarding, but it now requires the following configuration, which involves creating a named application
module. The details of usingangular.module will be explained in the upcoming chapters Modules, Dependency
Injection, andServices. For now, just treat the example below as some required boilerplate.
angular.module('app', []);
angular.module('app').config(['$controllerProvider', function($controllerProvider) {
$controllerProvider.allowGlobals();
}]);
Now that we have that out of the way, let's try out our noop controller.

ng-controller
As usual, the way to do it is with a directive. The ng-controller directive finds and invokes the controller function
passed to it by name.
<p ng-controller="EmptyController">
</p>
9|Page

As you may have expected, invoking this empty controller function does nothing. Now then, what are these
controllers? How do we use them?

Constructing the model


The conceptual overview in the official guide states that the controller's job is to expose variables and functionality
to expressions and directives. The functionality refers to callback functions. We will get to those in a little while.
Right now, let's talk about initializing variables, or preparing the model.
Keeping in mind that the Angular model is just ordinary JavaScript that can be reached through an
expression's scope, preparing the model is a piece of cake. Ordinary JavaScript? Sure, we can write ordinary
JavaScript. Let's add a simple string property to our empty controller.
function MessageController() {
this.message = "This is a model.";
}
Simple, right? Are we done? Does the assignment above create a model? Yes? No?
The answer is almost. When we can reach the message property through the view's scope, then it will be a model.
One way to accomplish this is to expose the entire controller as a property on the scope. This may sound like a big
deal, but if you know the secret syntax, it is easy to do.

Controller as propertyName
As explained in the API documentation for ng-controller, you can pass a Controller as propertyName expression as
the ng-controller argument. Please note that you need Angular version 1.2 or later to use this feature.
<p ng-controller="MessageController as controller">
{{controller.message}}
</p>
Look at that, we have just prepared model data using a controller.
Although the method of attaching properties directly to the this reference is straightforward, exposing the entire
controller to the view gives the misleading impression that the controller is part of the model, when traditionally,
the controller's role is just to prepare the model. Testing and debugging is often easier when you limit access to
only what a client needs and nothing more. Also, this approach adds noise to the view code, since all properties
must be accessed through the reference to the controller. View code is typically the most critical area of a web
application for noise; it's the first place where we are likely to have trouble understanding intentions at a glance.
Finally, controllers work hand-in-hand with the scope, so for instructional purposes it will be helpful to see a
reference to the scope and have fine-grained control over it. With this control, we can explicitly expose only what
we want to the view. Therefore, this book will prefer the controller style that explicitly manages the scope object.
The first question, then, is how we can get a reference to this scope object. Do we create it using thenew operator?
Do we request it from somewhere?
10 | P a g e

Dependency injection
No, we get it via dependency injection. You also may have noticed that I have not exhibited code that instantiates
a controller, such as var controller = new MessageController();. Who is creating the controllers used in the views,
then?
Angular is, of course. Angular is an Inversion of Control container that manages the lifecycle of
application components. When a new controller or other component is needed, Angular constructs one. This saves
us work, but more importantly, it makes it possible for Angular to inject resources, or dependencies, into our
components.
$scope
As a component that is managed by the dependency injection framework, our controller just needs a parameter
named $scope added to it. The naming of this parameter is critical. So critical, in fact, that if you minify your
JavaScript source code as part of your build, you will break the dependency injection mechanism. (Don't worry,
there is a workaround, explained in the Dependency Injectionchapter.)

function MessageController($scope) {
$scope.message = "This is a model.";
}
By adding the $scope parameter to our constructor function, we inform Angular that we want a reference to the
view's scope. Really, could this be any easier? Now, instead of declaring the messageproperty on this (the
controller), we declare it directly on the scope.
In the template, we remove the as controller from the ng-controller directive. The
expressioncontroller.message becomes just message, which is now the only property that we have attached to the
scope.

<p ng-controller="MessageController">
{{message}}
</p>
While both methods of exposing model data work, this book will mostly use the method that injects the
explicit $scope reference. Dependency injection is an integral part of using angular, as you shall see, so we may
as well get some familiarity with it.

Model-view-controller
The definition of a controller from the official guide also mentions exposing functionality to the view. Before we
move on to this area, I think it may be worth taking a moment to discuss how Angular controllers differ a bit from
the classical MVC pattern. (Or, skip the academics.)
According to the Wikipedia entry for model-view-controller (MVC), a controller mediates input, converting it to
commands for the model or view. However, it can be hard to understand the commands for the model or view
part in the context of Angular, since Angular's version of the MVC model is radically simplified, with anemic
models that as a rule contain no logic. In Angular, at least these days, the prevailing approach is to place all business
11 | P a g e

logic, also known as domain logic, inside the controller. In other words, Angular applications trend toward skinny
models and fat controllers.
If you are familiar with patterns such as rich domain model and Skinny Controller, Fat Model, I would expect you
to find Angular's approach to be a step backward. I think it's probably just a question of priorities. In client-side
programming today, the critical distinction is between declarative, DOM-oriented view code on one side, and
imperative, data-driven JavaScript code handling business logic and application infrastructure on the other. That's
a big win, and I'm happy that frameworks such as Angular are focused on it. Someday perhaps, separating business
logic from the other responsibilities of controllers will become more of a priority, and we will see a trend toward
richer models.

Functions
Let's write a controller that exposes a very basic function, simply to test that we can somehow invoke this function
from the view. As you may recall from the previous chapter, Angular did not permit us to declare and expose
functions within the view.
The controller below assigns a basic function to a property on the scope.
function CountController($scope) {
$scope.count = function() { return 12; }
}
Invoking the function within an expression is similar to normal JavaScript: We just use parentheses
<p ng-controller="CountController">
There are {{count()}} months in a year.
</p>
Note that the function is not simply invoked and forgotten, but is in fact bound to the model. What does that mean?
Well, Angular's binding infrastructure is something that you have probably begun to take for granted, but again, it
means that Angular will invoke the function not only when the view is first rendered, but anytime the associated
model is changed. In order to see this at work, we need to write a function that uses a model property.
The add function below uses two model properties that are declared on the scope, operand1 and operand2. Angular
will invoke the function and render the result whenever either or both properties are changed.
function AdditionController($scope) {
$scope.operand1 = 0;
$scope.operand2 = 0;
$scope.add = function() {
return $scope.operand1 + $scope.operand2;
}
12 | P a g e

$scope.options = [0,1,2,3,4];
}
Since we've already covered several examples of the input directive in the previous chapter, let's instead use
Angular's select directive to change the model values. You may have already noticed that the last line in the controller
prepares an options model, which we will use in a comprehensioninside this directive's ng-options parameter. The x
for x of our comprehension may seem redundant, since it just returns the original list of values, but the directive
requires us to write it nonetheless. (When your model is an array of objects, which is more typical, you might write
a comprehension that picks out a name property for the option label, using x.name for x. Refer to
theselect directive's parameters for more detail.)
<p ng-controller="AdditionController">
<select ng-model="operand1" ng-options="x for x in options"></select>
+ <select ng-model="operand2" ng-options="x for x in options"></select>
= {{add()}}
</p>
Ok, this works great. However, the design of the add function can be improved by generalization, which will come
in handy if we ever want to use it with properties other than operand1 andoperand2. Break out your refactoring
manual and roll up your sleeves for some parameter extraction.
function AdditionController($scope) {
$scope.number = 2;
$scope.add = function(operand1, operand2) {
return operand1 + operand2;
}
}

Callbacks
There is an example in the previous chapter demonstrating how an expression passed to ng-clickcan toggle a
boolean model property. It initializes the model, authorized, within an ng-initdirective, then manipulates it using a
simple, inline callback: ng-click="authorized = !authorized". Let's adapt the example by moving the model
initialization and toggle logic to its proper home, a controller.
function AuthController($scope) {
$scope.authorized = true;
$scope.toggle = function() {
$scope.authorized = !$scope.authorized
13 | P a g e

};
}
Now that toggle is a function available on the scope, the argument to ng-click looks like a function
invocation: toggle(). It isn't really an immediate invocation, of course. It's just a string that will be evaluated later,
when the user clicks.

<div ng-controller="AuthController">
<p>
The secret code is
<span ng-show="authorized">0123</span>
<span ng-hide="authorized">not for you to see</span>
</p>
<input class="btn btn-xs btn-default" type="button" value="toggle" ng-click="toggle()">
</div>

Conclusion
In this chapter, we introduced JavaScript into our usage of Angular, in the form of controllers, which in an MVC
pattern have the responsibility of preparing data for our views. Controllers make data available to views by declaring
properties on a scope object. In the next chapter, we'll take a closer look at scope objects, and learn how they are
organized as a hierarchy that roughly follows the structure of the DOM fragment managed by our application.

Scopes

What exactly is a scope in Angular? From the name, you might guess that it is a context for application state,
possibly provided to protect us from using JavaScript's much-maligned global scope. That sounds like a simple,
prudent thing for a framework to create, perhaps something we shouldn't even think about. Can we just move on
to the next chapter?
Not so fast. Although this will not be a long chapter, it does cover something very important: scope inheritance
and hierarchy. A typical Angular application might create a hierarchy of dozens, hundreds, or even thousands of
scopes.
Before we get started, let's set up the environment for this chapter's examples.

14 | P a g e

Setup
In the Basics chapter, we learned how to add the ng-app directive to an element in order to tell Angular which
part of your document it should process.

<body ng-app="app">
<!-- Other examples to be inserted here. -->
</body>
The argument to ng-app is the name of our application's root module. (The example module name,app, is just a
convention.) Angular modules will be covered in depth in an upcoming chapter. For now, just consider this some
bootstrapping boilerplate that you can ignore.
angular.module('app', []);
angular.module('app').config(['$controllerProvider', function($controllerProvider) {
$controllerProvider.allowGlobals();
}]);

$scope
In the last chapter, Controllers, we learned how to prepare the model by attaching properties to
a$scope reference. Let's repeat the exercise.
function NameController($scope) {
$scope.name = "First";
}
Using the ng-controller directive, we can invoke the controller function above in the context of a DOM element.
Any data that we assign to the scope provided to this controller will be available to us on and within
this p element.
<p ng-controller="NameController">
{{name}}
</p>

15 | P a g e

Collections

In the preceding chapter, Scopes, we learned that Angular creates a new scope each time you invoke a controller
constructor via ng-controller. There are other cases in which Angular creates new scopes, and perhaps the most
common is when working with collections of similar objects. Angular,unlike Backbone, does not have a
component named Collection. However, its extensive support for working with collections of like objects merits a
chapter, as you will see.

Set up
In addition to loading Angular from Google Hosted Libraries, the live examples in this page also load
the Bootstrap styles for better-looking tables and lists.
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.js"></script>

We then load our app module by passing its name to the ng-app directive. Our choice of the nameapp is a
convention, but not otherwise significant.
<body ng-app="app">
<!-- Other examples to be inserted here. -->
</body>
We are ready to proceed with our interactive exploration of collections, iteration, and Angular.

Iteration
In regular JavaScript, when you iterate over a collection of similar objects in a for loop, you might declare a local
variable to reference the current element. For example:
var items = [{name: "Item 1"},{name: "Item 2"}];
for (var i = 0; i < items.length; i++) {
var item = items[i];
}
document.body.innerHTML = item.name;
Imagine that items is a collection of unknown length, and that we need to iterate over its members, displaying
the name property of each.

ng-repeat
Just as Angular creates a top-level Angular scope for expressions to protect us from creating variables on
JavaScript's global scope, the built-in ng-repeat directive protects us from the situation shown in the first example,
by creating an Angular scope for each iteration of the loop.
<ol ng-controller="ItemsController">
16 | P a g e

<li ng-repeat="item in items" ng-bind="item.name"></li>


<li ng-bind="item.name"></li>
</ol>
For each element in the comprehension passed to it, ng-repeat creates a new child scope with a property as
specified in the comprehension. In this case, the property name is item, but it could be anything. Edit the
example above, changing the usages of item to something different, like i or x.

Object properties
The (key, value) in object syntax lets you loop over the properties of an object.
<table class="table table-condensed">
<tr ng-repeat="(propertyName, propertyValue) in {b: 'two', a: 1.0, c: 3}">
<td ng-bind="propertyName"></td>
<td ng-bind="propertyValue"></td>
</tr>
</table>

17 | P a g e

Generally speaking, the goal of modules is to achieve a separation of concerns by defining public APIs and
limiting the visibility of behavior (functions) and data (properties and variables). Most programming platforms
include built-in support for modules, making their use something to take for granted. Client-side JavaScript
currently does not, creating a situation in which debates rage over the pros and cons of the popular add-on
solutions, such as CommonJS and Asynchronous module definition (AMD).
Keep in mind when making comparisons to other solutions that Angular's module system is not a module loader.
It does not load source code from files or the internet for you. What Angular provides is a built-in, proprietary
module solution that works closely with its similarly built-in and proprietary dependency injection solution.
Together, the two systems provide an impressive amount of general-purpose infrastructure. Although learning to
use this functionality is within the ability of any developer, the question is, why do we need it?
Modules and dependency injection are ordinarily an "all-in" proposition, but as we have seen, Angular allows us
to get started without using its module system. So far, we have been able to accomplish quite a lot simply by
defining controllers as named functions on the global scope. This works because with a little configuration,
the ng-controller directive searches for controller functions globally as well as in the module system. The lesscomplicated global approach to using Angular is permitted, but only up to a point.

Why use Angular modules?


In order to move beyond Angular's basic features, you will need to master its module system. This book does not
seek to convince you of the intrinsic value of Angular's modules or dependency injection. When it comes to the
general problem of managing complexity in your JavaScript projects, you should arrive at your own best practices,
and a simpler approach may be better. This book covers modules and dependency injection as necessary to use
Angular.
Therefore, let's survey the important features that require us to use the module system:

Specialized components - To define your own controllers, directives, filters, and animations, you must
use the module system. (Controllers may be excepted, as mentioned above.)
Dependency injection - Although services are just ordinary JavaScript objects and functions, only
services created with the module system can be easily injected with their dependencies, as well as
themselves made available for dependency injection.
External modules - There is an impressive ecosystem of free, open-source Angular add-ons, both from
the core team and third parties. To use any of these libraries in your application, you must use Angular's
module system.
Load-time configuration - Angular's module system provides access to lifecycle hooks into Angular's
internal configuration, as well as the configuration of add-on modules. The latter will be demonstrated at
the end of the final chapter when we configure a custom HTTP header.
Testing - Angular's impressive testing infrastructure leverages its dependency injection system, which in
turn depends on its module system.

An upcoming chapter, Services, will demonstrate how to define providers for custom JavaScript components. This
chapter will show how to define a controller as well as to load external modules at the same time that it teaches
you the basics of the module system.

18 | P a g e

An Angular application can be initialized with only one root module. In our examples this module will be
named app by convention. This name isn't significant, but it is commonly seen in much of Angular's
documentation.
angular.module('app', []);

In the module.js example above, please take careful notice of the second argument to the modulemethod.
Although it is just an empty, innocent-looking array ([]) in this usage, the presence of this second argument is
extremely important. If you omit it, the behavior of angular.module changes radically. Talk about questionable API
design! When you call angular.module with the second argument, the function operates in create mode, and
creates a new module named app if no module with that name already exists. However, if you
call angular.module without the second argument, it operates in lookup mode. If a module with the
given name already exists, it will return it; if not, it throws an error that helpfully mentions including the second
argument. We've got it right in this example, but just be aware of this important difference in your own code. As
for the array argument, it is used to import External modules, which we will discuss presently, using Angular's
animation module for our example.

Loading the application module


In the HTML document that hosts our application, we can instruct Angular to load the application module by
passing its name to the ng-app directive.
<body ng-app="app">
<!-- Other examples to be inserted here. -->
</body>
Any components that we add to our application module will be available for use. Let's see what it looks like to
define a controller within a module rather than on the global scope.

Defining a controller
The API for module includes functions for defining specialized Angular components. The only specialized
component that we are familiar with so far is the controller, so let's use the controllerfunction to create one. First
we need to obtain a reference to the application module. As explained above, we must
call angular.module without its second argument, so that it operates in lookupmode.
var app = angular.module('app');
app.controller('MessageController', function($scope) {
$scope.message = "This is a model.";
});
Now, somewhere within the element on which we invoked ng-app="app" , we can use ng-controllerto load our
controller.
<p ng-controller="MessageController">
{{message}}
</p>
As you can see, defining a controller within a module is a little more work than defining one on the global scope,
but not too bad at all.

19 | P a g e

Chaining definitions
Let's say that we need to define two controllers for the template below.
<p ng-controller="MessageController">
{{message}}
</p>
<p ng-controller="AnotherMessageController">
{{message}}
</p>

Loading modules
Animations is a newer Angular feature that was added as a separately packaged module namedngAnimate. The
first step to using animations is to include the JavaScript file containing the module. The source code for the
module is part of the core Angular project, but it is distributed as a separate file, as shown below.
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular-animate.js"></script>

It's time to really use the module function's second array parameter, to which we passed an empty array in the
earlier example. This is where we can declare our module dependencies.
angular.module('app', ['ngAnimate']);
We have loaded ngAnimate into our application module. In our templates, the directives ng-show,ng-hide, ngclass, and several others will now check for both CSS and JavaScript animations that can be applied to DOM
events like add, enter, leave, move, and remove. Applying animations to supported DOM events is transparent in
the sense that no changes are required to our template code. If no animation code is present, either as CSS or as
JavaScript registered via module.animation, our directive code will behave normally.
<input type="checkbox" ng-model="showMessage">
Check the box to show the message
<h2 ng-show="showMessage">
The secret message.
</h2>

20 | P a g e

Angular's built-in directives, such as ng-bind, ng-model, and input, have played a starring role in this book since
the very first chapter, Basics. In fact, the Collections chapter focuses almost entirely on a single (quite powerful)
directive, ng-repeat. It would seem that Angular's list of built-in directives would contain a solution for every
situation, but of course this isn't true. While Angular was conceived as a way to enable non-programmers to build
dynamic web pages, it evolved into a platform that gives web developers the power to extend and customize
HTML. This means creating your own custom directives, which is exactly what we'll do in this chapter.
In its simplest form, creating a custom directive is very similar to creating a custom filter, which is why we
learned about filters first, in the preceding chapter. The outer function that we pass to thedirective function is a
dependency injection wrapper and factory function, also known in the Angular documentation as a recipe. It is
called at most once, or never if the directive is not used, as we learned in the chapter on Services. Inside this
factory function is another function, which will be called by Angular. This inner function is where we do the
actual work of the directive. It is called thelink function.

directive
The appropriately-named directive function for registering custom directives is part of themodules API, so we need
to begin by creating a root module for our application.
angular.module('app', []);
We load our root module by passing its name to ng-app.
<body ng-app="app">
<!-- Other examples to be inserted here. -->
</body>
And with that, we're ready to create a directive. Let's start with a very simple directive named hello.
angular.module('app')
.directive('hello', function() {
return function(scope, element) {
element.text("hello");
};
});

21 | P a g e

Potrebbero piacerti anche