Introduction to Angular

Angular Architecture

Angular Components

Getting Started with Angular: The Angular Seed

The Angular team provides a template project known as the Angular seed to be used as a starting point for a new Angular.js application. This project is an ideal starting point to begin using Angular.

AngularJS Modules

A module in AngularJS is used to group different parts of an Angular app like controllers, services, directives, etc. Modules represent independent parts of the application that can make use of other modules to access new functionality. You can compare AngularJS modules with .NET assemblies.

You can define a module by using the angular.module function. For instance, an Angular app has typically one root module used to bootstrap the app:

var myApp = angular.module("myApp",/* dependencies */[]);

You can add AngularJS components to a module by using different methods within the module object. For instance, to add a controller to a module you use the app.controller method:

The ng-app Directive

The ng-app directive is the entry point to your AngularJS application and should point to the boostrap module:

<htmlng-app="myApp"><head>...</head><body>...</body></html>

AngularJS Controllers and the Scope

Controllers in AngularJS work much in the same way that they work in any MVC framework. They work as an intermediary between the domain model and the views. They perform operations on data of the domain model and prepare it for a given view, they create a scope to expose data to the view. The view in its turn can bind to any piece of data exposed via the scope object.

The ng-controller Directive

The ng-controller directive lets you bind a view to a given controller, that is, a fragment of HTML code to a controller and its scope. For instance:

<divng-controller="MyController"><h1>{{barbarian.name}}</h1><!-- note the use of ng-src to delay the request for an image until the binding is resolved --><!-- when the binding is resolved then the src will be filled with the image url --><imgng-src="{{barbarian.avatar}}"></div>

The ng-repeat directive

You can use the ng-repeat directive to repeat a given html template for every item within an array. For instance:

<divng-controller="MyController"><h1>{{barbarian.name}}</h1><!-- note the use of ng-src to delay the request for an image until the binding is resolved --><!-- when the binding is resolved then the src will be filled with the image url --><imgng-src="{{barbarian.avatar}}"><h2>Inventory</h2><ul><ling-repeat="inv in barbarian.inventory">
{{inv.name}}
</li></ul></div>

<divng-controller="MyController"><h1>{{barbarian.name}}</h1><!-- note the use of ng-src to delay the request for an image until the binding is resolved --><!-- when the binding is resolved then the src will be filled with the image url --><imgng-src="{{barbarian.avatar}}"><h2>Inventory</h2><ul><ling-repeat="item in barbarian.inventory">
{{item.name}}
<buttonng-click="sellItem(item)"></button></li></ul></div>

AngularJS Built-in Directives

Directives are the way Angular extends HTML with new behavior and functionality. You can create directives that are either elements, attributes, CSS classes and even comments.

Event built-in directives let you handle DOM events

ngClick, ngDblClick

ngMousedown, ngMouseup, ngMouseover, etc

ngChange (requires the ngModel directive within the same element)

ngApp represents the entry point of your Angular app

ngBind tells angular to replace the text content of an HTML element with the value of a given expression f.i. ng-bind="barbarian.name". Typically you don’t use ng-bind="expression" directly but {{expression}}. It is preferable to use ng-bind instead of {{expressin}} if a template is momentarily displayed by the browser in its raw state before Angular compile it; since ng-bind is an attribute it is not visible while a page is loading. (An alternative solution to this would be to use ng-cloak)

ngBindTemplate tells angular to replace the text content of an HTML element with the interpolation of a given template f.i. ng-bind-template="{{barbarian.name}} is fierce and weights {{barbarian.weight}}"

ngBindHtml (part of the angular-sanitize module) evaluates an expression and inserts the resulting HTML into the element in a secure way (sanitized using the $sanitize service). For instance: ng-bind-html="snippetWithUnsafeHtml"

ngBindHtmlUnsafe like above but without the sanitization step so you can use it on markup that you trust

ngShow and ngHide let you show and hide parts of the DOM based on expressions

ngCloak allows you to hide portions of your page (or the whole page) while angular is loading to avoid showing portions of the DOM that haven’t been evaluated by Angular yet.

*ng-class lets you add classes dynamically by binding an expression that represents all classes to be added

ngClassEven and ngClassOdd work with ng-repeat to provide different styles to odd/even elements of an array when rendered in the DOM.

Tips About How to Use Controllers

Don’t manipulate the DOM in controllers, use directives for that, a controller should limit itself to being an intermediary between the domain model and the view. Just populate the $scope and expose the data you need.

AngularJS Services

A service in Angular is used as a way to encapsulate reusable business logic that can then be injected as a collaborator in controllers or other services.

Using services within your Angular applications will result in a clearer, more organized application with smaller, reusable and testable components.

Creating Your Own Services

You can create a service using the service or the factory functions. Note that, because services are singletons is important that they are stateless to avoid coupling different parts of your application with shared state. The recommended ways to declare and register services looks like this:

Once registered like this a service can be used by other angular components such as controllers or other services:

app.controller('MyController',functionMyController($scope, logger){// you can start using the logger service right here})

Angular Built-in Services

Angular comes with a host of built-in services which can be easily identified by the $ character that precedes them like $scope. This section will briefly describe some of these built-in services

The $http and $q Services

You can use the $http service to make HTTP requests to any server via the browser XMLHttpRequest object and JSONP:

app.factory('someService',function($http, $log)){return{get:function(onSuccessCallback, onErrorCallback){// you can use $http directly as a method$http({method:'GET', url:'/data/someData.json'}).success(function(data, status, headers, config){
$log.info(data, status, headers, config);onSuccessCallback(data)}).error(function(data, status, headers, config){
$log.warn(data, status, headers, config);onErrorCallback();})}}}// when using this service from other // component you would need to pass callbacks
someService.get(/*sucess*/function(data){// do something with data},/* error */function(){// oh no! There was an error!})

We can also leverage the $q service to avoid the need of using callbacks when handling http requests or any other asynchronous operation. The $q service allows you to create promises:

app.factory('someService',function($http, $q)){return{get:function(){var deferred = $q.defer();// you can use $http directly as a method$http({method:'GET', url:'/data/someData.json'}).success(function(data, status, headers, config){
deferred.resolve(data);}).error(function(data, status, headers, config){
deferred.reject(status);})// return a promisereturn deferred.promise;}}}// we can use this service from another component// without the need of callbacks by taking// advantage of the returned promise:
someService.get().then(function(data){// use something with data FTW!!!}).error(function(statusCode){// oh no! An error!!!});

Note how we used the also built in $log service to log information in a similar fashion to console.log in the browser.

For more detailed information about these services refer to the AngularJS documentation:

The $resource Service for RESTful Services

You can use the resource service to consume RESTful APIs. In order to start using it within your application, include the ngResource (angular-resource) module within your application and use it as detailed in the example below:

app.factory('someResfulServiceFacade',function($resource)){return{get:function(id){return$resource('/api/resource/:id',{id:'@id'}).get({id: id});}}}// and you can use it like this:var resource = someRestfulServiceFacade.get(1);// this is async and works sort of like a promise // or like an actual promise like this// note how we explicitely get a promise via $promise
someRestfulServiceFacade.get().$promise
.then(/* success */function(resource){// this resource object has a Resource type that wraps the server response}/* error */function(response){});

Binding on the Fly With The $compile Service

The $compile service is used heavilily internally by AngularJS to look for directives within a page and process them. Additionally, Angular exposes this service so you can use it with custom directives or whenever you want to bind markup to data on-the-fly. For instance:

The $timeout Service

The $timeout service is very similar to JavaScript’s setTimeout function, but with the different that AngularJS can track changes produced by the timeout callback (otherwise the UI will not be refreshed until another part of the $scope changes):

var promise =$timeout(function(){// do something
$scope.name ='Jaime';},2000);// you can use the promise to cancel the execution of the// timeout callback
$timeout.cancel(promise);

The $exceptionHandler Service

The $exceptionHandler service provides you a hook to handle AngularJS exceptions. We can override it to take control of exceptions that occurr in AngularJS ourselves:

$rootElement: provides access to the element that is decorated with the ng-app directive.

AngularJS Routing

AngularJS routing allows you to provide a way to navigate within the different views of your single page application. Using the routing APIs you will be able to define URL routes that will map to the views within your app.

In order to start using routing you will need to have an html ng-view element that will act as a placeholder for the views:

<body>
...
<ng-view></ng-view>
...
</body>

The routing system not only allows you to map URLs to views but compose your entire single page application by composing controllers with templates to produce views. You will need to add ngRoute module (angular-route.js) and configure your routes like this:

var myApp = angular.module('myApp',['ngRoute']).config(function($routeProvider)){
$routeProvider.when('/speakers',{
templateUrl:'templates/speakers.html',
controller:'SpeakersCtrl'});
$routeProvider.when('/sessions',{
templateUrl:'templates/sessions.html',
controller:'SessionsCtrl'});// You can also add routes with parameters
$routeProvider.when(/sessions/:sessionId,{
templateUrl:'template/session.html',
controller:'SessionCtrl'})// and add the default route to redirect the user to// if a route is not found
$routeProvider.otherwise({redirectTo:'/sessions'});});

After configuring a route, you will be able to reach it via an a tag as illustrated below:

Additionally, the routing engine within AngularJS will keep your browser history as the user would expect (whenever you navigate within your app and then click on the back button, the browser goes to the previous view within your Angular app instead of getting out of your site).

In the previous example I used a :sessionId in one of the routes that can be used as a parameter. In order to extract this route parameter from your route within a controller you can use the $routeParams service:

These and other parameters from the route can be accessed in any controller with the help of the $route service:

myApp.controller('SpeakerCtrl',function($scope, $route){
$scope.greeting = $route.current.greetings;// to get params from the query string -> /speaker/1/?showBio=true
console.log($route.current.params.showBio);// => 'true'// it also works with route params :param
console.log($route.current.params.speakerId);// => '1'// We can also use pathParams// but this only works for parameters that are path of the route
console.log($route.current.pathParams.speakerId);// => '1' });

Reloading a View

Sometimes you’ll want to reload a view without reloading your entire app. If you want to do that the $route service provides the reload method that you can use for this very purpose.

Enabling HTML5 Routing

You can configure your routing to avoid the need of using the hashtag # by using the $locationProvider service:

This will allow you to use normal urls instead of hashtag prefixed urls for deep linking within your app:

<ahref="/sessions">Sessions</a>

AngularJS will use this approach within browsers that support HTML5 routes and will include the hashtag with browsers that do not support this style of routing. Important: It is worthy of note that if you save a url with a deep link and then try to navigate to it directly (instead of reaching it from within the angular app via a link tag) the browser will make a GET request to your server with that very url (e.g. myapp.com/sessions), in that case you will need to configure your server to return the root html file instead of the partial template.

Dynamic Templates

Instead of specifying a url for a template you can pass any string within the template property. This allows you to generate templates on the fly:

var myApp = angular.module('myApp',['ngRoute']).config(function($routeProvider)){
$routeProvider.when('/speakers',{// you could generate this on the fly via a service
template:'<h1>Speakers</h1>',
controller:'SpeakersCtrl'});});

Avoid Partial View Load With Long Running Requests

If you experience a problem when loading a view because the associated JSON data that is going to be bound to a template takes a while, and thus an unpopulated view appears to the user you can use the resolve routing option. If so, the resolve option must contain a function that returns a promise. AngularJS will wait for the promise to be completed before rendering the view:

The $location Service

The $location service allows you to navigate within your angular app in a programmatic fashion, that is, from code instead of using link tags. The $location service provides access to the URL that is currently being displayed in the browser a is linked to it so that changes done via the $location service are also reflected in the browser URL.

The $location service also allows you to switch to another url without putting it in the browser history. You can do that by calling the $location.replace() method before changing the url.

For more information regarding the $location service refer to the AngularJS docs.

Creating Custom Directives

AngularJS allows you to create custom HTML tags with an associated look and feel and behavior via custom directives. Additionally you can use directive to create custom evens (like ng-click) or to observe and react to changes in the model. This allows you to create a domain specific language over HTML and be more intentional about the specific domain of the web application that you are developing. AngularJS directives are heavily inspired by the Web components standard that is under development.

You can create a new directive by using the directive method. Look closely at the different examples because they use different options and provide a little advice as to when and why:

myApp.directive('myDirective',function($compile){// return the directive definition objectreturn{
restrict:'E',// restrict directive to 'E'lements (by default it is 'A'ttribute, it can also be 'C' for class, 'M' for comment, etc)
link:function(scope, element, attrs, controller){var markup ="<input type='text' ng-model='name'> {{name}}<br/>";var compiledMarkup =$compile(markup);// compile markupvar boundMarkup =compiledMarkup($scope);// apply scope to markup
angular.element(element).html(boundMarkup);}};});// this is equivalent to:
myApp.directive('myDirective',function($compile){// return the directive definition objectreturn{
restrict:'E',// restrict directive to 'E'lements (by default it is 'A'ttribute, it can also be 'C' for class, 'M' for comment, etc)
template:"<input type='text' ng-model='name'> {{name}}<br/>"};});// you can also point the template to a URL like this:
myApp.directive('myDirective',function($compile){// return the directive definition objectreturn{
restrict:'E',
templateUrl:'/templates/directives/myDirective.html'};});// you can use the replace property // to generate valid HTML (replace the whole directive element for valid markup)
myApp.directive('myDirective',function($compile){// return the directive definition objectreturn{
restrict:'E',
replace:true,
templateUrl:'/templates/directives/myDirective.html'};});

You can then use it in your html:

<my-directive/>

As you can anticipate, this allows you to create multiple directives to build a very intentional domain specific markup:

Using a Specific Scope Within a Directive

To this point we have been using the same $scope as the one in which the html directive is placed. This is not what you want to do since it will make the directive not reusable, that is, the directive depends on outer scope it has no control over. Moreover, it may couple multiple directives together (changing binding sources in one directive may affect other directives). Instead we can define a separate scope for the directive:

myApp.directive('myDirective',function($compile){// return the directive definition objectreturn{
restrict:'E',
templateUrl:'/templates/directives/myDirective.html',
scope:{// now the directive has its own isolated scope}};});

Once you isolate the scope of a directive it becomes necessary to be able to pass data to the directive in some way, you can do this via html attributes that can be bound to the scope declared within the directive. For instance, if we have an element directive with an session attribute:

<session-detailssession="session"another-parameter="cheese"/>

We can bind that argument to the directive scope by declaring the session variable in the scope property of the directive definition object with a value of =session (or = if we are using the same name in the scope and in the attribute):

myApp.directive('sessionDetails',function($compile){// return the directive definition objectreturn{
restrict:'E',
templateUrl:'/templates/directives/sessionDetails.html',
scope:{
session:'=session'// we can also use the shorcut '=' since it is the same name 'session'
anotherParameter:'=anotherParameter'// note how another-parameter becomes anotherParameter}};});

In addition to binding properties with '=' to our scope we can use '&' and '@' as described in the example below:

<upvoteupvote="session.upvote()"downvote="session.downvote()"count="{{session.voteCount}}"/><!-- if we were to use count with '='
<upvote upvote="session.upvote()" downvote="session.downvote()" count="session.voteCount"/>
-->

myApp.directive('upvote',function(){return{
restrict:'E',
template:'/templates/directives/upvote.html',
scope:{// the '&' means that we expect to bind this scope property// to a function that we will execute within the context// of the **outer** scope instead of the directive scope
upvote:'&',
downvote:'&',// the '@' means that we expect to bind this scope property// to a string. If we want to bind this property of the inner// scope with a property of the outer scope then we will need// to evaluate it in the html attribute e.g. {{property}}
count:'@',// count: '=' // this would bind the property value from outer to inner scope}};});

Handling Events With Directives

In addition to create directives to create our own custom HTML elements with a specific view and behavior, we can create directives that handle events and inject behavior in other existing elements.

...

...

Transclusion

Transclusion is the act of embedding html within a directive and injecting this html within the template of the directive. For instance:

It is very important to note that transclude makes the contents of a directive with this option have access to the scope outside of the directive rather than inside. So the transcluded content will use the outer scope and not the scope within the directive (if it has one).

{% blockquote %}

The transclude option changes the way scopes are nested. It makes it so that the contents of a transcluded directive have whatever scope is outside the directive, rather than whatever scope is on the inside. In doing so, it gives the contents access to the outside scope.

This behavior makes sense for a directive that wraps some content, because otherwise you’d have to pass in each model you wanted to use separately. If you have to pass in each model that you want to use, then you can’t really have arbitrary contents, can you?

Tips and Tricks

Avoiding Clipping behavior When a Page First Renders

Some times you will notice that the first time the page renders for your angular app you will get a clipping/flicker behavior. In order to avoid that you can use the ng-cloak directive:

{% blockquote %}

The ngCloak directive is used to prevent the Angular html template from being briefly displayed by the browser in its raw (uncompiled) form while your application is loading. Use this directive to avoid the undesirable flicker effect caused by the html template display.

Writing Clean Code in AngularJS

Separation of Concerns

Separating concerns within your application will make it easier to maintain and extend, you’ll be able to reuse more code and it will be easier to test (since it is easier to test parts of code that are independent from each other). In summary, separation of concerns lets you minimize the complexity of your application by creating components that do one thing and one thing only.

AngularJS is built with separation of concerns in mind but you can still violate the separation of concerns principle and unnecesarily increase the complexity of your applications. In order to follow the SoC principle you should:

Would you like to receive more articles like this one on programming, web development, JavaScript, Angular, developer productivity, tools, UX and even exclusive content like free versions of my books in your mailbox? Then sign up to my super duper awesome inner circle.

Did Ya Know I've Written Some Books?

I have! The JavaScript-mancy series is the lovechild of three of my passions: JavaScript, writing and Fantasy. In the pages of each one of the books of the series you’ll find a breadth of JavaScript knowledge, delivered with a humorous and casual style of writing and sprinkled with Fantasy at every turn.

They are the weirdest and quirkiest JavaScript books you'll ever find. There's nothing out there quite like it.