Saturday, March 1, 2014

Use AngularJS to Power Your Web Application

AngularJS is a truly amazing approach to developing JS-heavy web applications

AngularJS, by Google, is a well-organizedwell-testedversatilepowerful and flexible JavaScript MVC framework for building rich client-side applications. You still may need to have a server-side backend, but the majority of the user-interactivity logic will be delegated to the client-side. This includes stuff like form submissions which are handled via AJAXmodel validationstemplate handling and data-binding. If these things are foreign to you then read onwards and see how you can benefit from building web applications in a much more radical way.

Last Updated

This page was first published on August 15th 2012 and was last updated on October 29th 2012.

Table of Contents

About this article

This article briefly outlines what Angular can be used for and the basics of how it works. The article coverscontrollers and scopeservicesmodelstemplatesdirectivesfiltersmodules and configurations.
This article also explains how angular can be used with MooTools and JQuery in harmony.

Web Applications (not Websites)

When you decide to build a website using angular the major question to ask yourself is that is this a website that requires valid HTML or is this a web application that focusses more on functionality then markup. Angular works with templated HTML code and JSON data. The major impact of the approach of how angular, and all other client-side MVC frameworks, handle its logic mean that structure and data are designed to be separated from each other. This results in templates (HTML) and data (which is fetched as JSON) bound together to provide a working and interactive webpage. Therefore the markup fetched from the server is meaningless on its own without Angular parsing it and you need to have a client that supports JavaScript. Thus, search engines need to work extra in order to get a full representation of the data--so for now it's not a good idea to use angular if you're building a website that relies on search engines to function. So if you're building a web applicationadmin website or single-page website then you've chosen a great tool to do the job.

So how does it work?

Angular works by separating application logic from data on the client-side and structuring a client-side web application with use of directivesfiltersbindings and binding-specific operations. Controllers, Services and Models are used to glue all the logic and data operations together. As mentioned, data and logic are separated so this means that your data (the dynamic stuff), your HTML templates (the static stuff), and your logic (the controllers and binding markup) work together to make the application work. The nice thing is that if all the non-dynamic stuff can be cached for longer and your dynamic responses are smaller. This is great for caching server-side responses and greatly reducing the amount of work that the server has to do to generate the HTML response. In fact if you think about it, the majority of the data fetched for a HTML page is either redundant or stateless ... so why not just make it 100% static? Angular does this and it does it well.
Just like any MVC architecture, URL paths are routed to controllers and the parameters are available within the controller method. Angular also provides support for resources (models) and it does a good job by reducing the amount of code required for boilerplate model code for querying the server back and forth. It also reduces the amount of code required for handling DOM bindings with data and HTML elements.
Once the page is ready, angular does it's magic by building the page with its various components. Lets take a look at what they are.

Getting Started

Setup your website and include angular within your HTML code with a JavaScript script tag to include the library into the website. It's best that angular is imported before all other libraries and code.



Modules

Modules are used to fully encapsulate all the angular code of your application into one entry point. The more recent builds of angular include module support which is kinda like namespacing mixed in with dependency injection (DI) and error trapping. Older versions of Angular didn't include this. There are various blog article posts, videos and demos out there that are teaching how to use an older version of angular. This may get confusing when setting up your application with a fresh download of angular).
Modules are used so that your application (as well as discrete parts of your application) can be separated into distinct parts which can be loaded and executed in different order. So you could have a directives module which can be set to run just before the ui module is run, thus ensuring that your resulting application DOM is in proper shape for your ui code to run.
The first thing you need to do when setting up your angular app is the following in your main layout file (I'm assuming you've already included angular into your website as JavaScript script tag).

 data-ng-app="YOUR_APP_NAME">
You can also use other variants in your HTML for setting your app name, but I feel HTML5 data attributes are the way to go.
Next, include a new javascript file into your website and set this code:
var App = angular.module('YOUR_APP_NAME', ['ngResource']);
This will create a global module for your app where you can create routesmodelsfilters and directives. TheApp variable is accessible throughout your application and the ['ngResource'] definition array defines all the other modules and dependencies that must be loaded prior to this module being activated. In this casengResource is an additional module that defines functionality for creating resources (models) in angular.
Any additional models can be defined using the same syntax, but you must define the module name as a different name as any other module that has been defined. If you create another module with the same name then it may not active (or the previous module may not activate instead). If you wish to make a new module activate after the main application module then just define the new module and set the name of the application module as a dependency.
Keep in mind that a module can easily break (if there is erroneous code within), and modules are designed to contain their own errors, so finding an error may be difficult since you may be left with an empty page.

Bindings, Expressions & Angular Magic

Bindings are very very powerful. They drastically reduce the amount of HTML code required and they completely separate application logic from data. Angular comes with expressions which are apart of its general markup for HTML and are bound to the scope variable which is where the data binding takes place. This involves data bindingtwo-way data bindingconditionalsfor in and foreach loopsmodel binding and so on.
Here is an example to list all the records in an ordered list we can use the following (this is what angular expression are):
class="records" data-ng-repeat="record in records | orderBy:orderProp">
{{ record.title }}
The inner block (the h5 tag stuff) will be repeated for each record found within the records object (which is apart of the $scope variable). Finally the orderBy:orderProp specifies which property (in this case the title) can be used to sort the records.
And the JavaScript to setup the data is as follows (this is the data binding):
$scope.records = [{ title : 'one' }, { title : 'two' }, { title : 'three' }];
All that's missing is the controller (this is covered later on in this article). The beauty about this approach is that (as you can see) the data (the Model) is 100% detached from the markup (the View) and the data itself can be retrieved and cached from an external source while being handled and tweaked by a logical controller (the Controller). Hence we have an awesome MVC framework.

Dependency Injection

Dependency Injection (DI) is, in angular, method of organizing how components, modules and variables are loaded to various parts of your angular app. It's a bit confusing at first, but its really there to make things more organized and for testing to be easier. All of your components within your app are to be injected into your controllersmodule configuraitonsdirectivesfiltersresources and routes. Here's an example of a dependency injection for a controller:
//the controller definition
var Ctrl = function($scope, $http, $location) {
  //now you can use any of the injected variables

  //to change the URL after something has happened then you can use $location
  $location.path('/path/to/new/page');
}
//and now the injection of the variables
Ctrl.$inject = ['$scope','$http','$location'];
The benefit to DI is that you can totally isolate all of your services, controllers, resources, directives, filters into their own contained environments with no global variables. This makes testing much easier. It also facilitates ordering between code blocks so that once a particular dependency has been injected then it is guaranteed to be there for use within the next code block.

Routes

Routes are used to map which path matches are linked to which controller. When you access a URL (by clicking on a link or putting in the URL), angular will first check to see if its defined and, if not, then it will delegate the event to a standard webpage view (access the html page normally) or do nothing (if it was a hashbang URL). This is nice since you don't have to manage any URL changes yourself atop of the angular routes.
Routes are defined directly from the application module with the following syntax. NOTE: Route paths do not have anything to do with hashbangs (you can toggle hashbangs on or off via HTML5 mode).
App.config(['$routeProvider', function($routes) {

  $route.when('/',{
    templateUrl : '/templates/home.html',
    controller : HomeCtrl
  });

  $route.when('/register',{
    templateUrl : '/templates/register.html',
    controller : RegisterCtrl
  });

  $routes.otherwise({
    redirectTo : '/'
  });

}]);
You should be able to create routes anywhere in your app code--this is nice when you create controllers in separate Javascript files which include their own routes.

Controllers & Scope

Controllers are where the logic of your application happens. Plugins, Widgets and DOM-specific code shouldn't be included here since that stuff is meant for directives. First, start by setting up the controller (each controller function is basically the action itself).
var SomeCtrl = function($scope, $http, $location) {
  $scope.value = 'some value';
};
SomeCtrl.$inject = ['$scope','$http','$location'];
The $scope is specific to where the controller is hooked into within your webpage. And any properties set for the $scope variable will then evaluate within your webpage. Here's an example of placing a binding in the HTML and then setting its scoped property.
class="header">{{ title }}
Now here's the HTML:
$scope.title = 'this is awesome';
Now the DOM will be updated and your HTML code will look like this:
class="header">this is awesome
More information is explained within the directives area.

For when your $scope variable data changes, but angular doesn't pick up on it.

Sometimes angular won't notice when you change a property in your $scope variable so in this case you will need to force angular to pick up the change.
Try running these methods:
//lets say you have 
{{ someVar }}
inside your HTML.
$scope.someVar = 'value'; //if a scope digestion is already going on then it will get picked up and you won't //have to call the $scope.$apply() method if(!$scope.$$phase) { //this is used to prevent an overlap of scope digestion $scope.$apply(); //this will kickstart angular to recognize the change }
Make sure to read more about this on the follow up article, More AngularJS Magic to Supercharge your Webapp, which goes into even more detail about how to properly digest and apply binding changes.

$rootScope

All $scope data is inherited off the $rootScope variable, so if you want to share reusable code across all your $scope objects in all your controllers then you can do it by setting properties of the $rootScope variable.
App.run(['$rootScope', function($rootScope) {
  $rootScope.sharedFunction = function() { ... };
}]);

Controllers

Finally, there are two ways to register a controller to the application:
Include the Controller within your application HTML
A controller can be set using an angular directive within a HTML tag.
data-ng-controller="SomeCtrl">...
Assign a Controller to be apart of a route
You can also define a route and specify the controller that handles the request:
$routes.when('/some/path',{
  controller : Ctrl,
  templateUrl : '/templates/controller.html'
});

Services

Angular Services is an amazing approach to abstracting shared code and functionality across your application. It ties directly into the dependency injection feature that angular provides and can be used directly apart of the module object.
//define the service
App.factory('myService', ['myOtherService', '$location', function(myOtherService, $location) {
  return function(input) {
    //do something with the input using the myOtherService or the $location objects.
    return input;
  };
}]);

//use the service within the controller
var HomeCtrl = function($scope, myService) {
  var input = '123';
  input = myService(input);
};
HomeCtrl.$inject = ['$scope','myService'];

//use the service a directive
App.directive('myDirective', ['myService',function(myService) {
  return {
    link: function($scope, element, attrs) {
      var input = '123';
      input = myService(input);
    }
  }
}]);
The myService is provided into the controller as a function (or object depending on what the service declaration returns) and can be used directly. The nice thing is that there is one entry point to the service and this means that it can be tested very easily.

Models

Models are used the same way that models are used just as a model is used in Rails or any other MVC framework. They're also defined in the same manner as angular services are as well as injected into the application. All regular getter and setter operations for model properties exist and all RESTful operations are defined and access the server backend to do their storage operations. Your server-side application needs to be coded to handle each of the REST operations for each model (POST create, GET show, GET index, PUT/PATCH update, DELETE destroy).
Here's how you define a model in angular:
App.factory('ModelName', ['$resource', function($resource) {
  $resource.url('/path/to/model/controller/:id',{
    id : '@id', //this binds the ID of the model to the URL param
  },{
    query : { method : 'GET', isArray : true }, //this can also be called index or all
    save : { method : 'PUT' }, //this is the update method
    create : { method : 'POST' },
    destroy : { method : 'DELETE' }
  }
}]);
This will create a model called ModelName with the REST actions queryshowsavecreatedestroy all targeted towards the /path/to/model/controller/:id. The :id param is only used for getsave and destroy REST calls. When an :id value isn't present then it will not be used in the URL and angular will strip and trailing slashes and whitespace from the URL so effectively you'll end up having a URL such as/path/to/model/controller for REST calls such as query and create (which is how REST expect for them to be). All of the actions defined can be called directly from the model, but in order to have access to the model as a variable you must include it as a dependency injection:
var SomeCtrl = function($scope, $http, $location, ModelName) {
  //now you can use ModelName to do your business
};
SomeCtrl.$inject = ['$scope','$http','$location','ModelName'];
Once you have access to the model you can call all the actions that you have defined in your resource definition as well as as a few others. Here are some examples:
//list all the records on the page
var results = ModelName.query({ search : 'all' }, onSuccessFn, onFailureFn);

//get a specific record
var record = ModelName.get({ id : 123 }, onSuccessFn, onFailureFn); //onSuccessFn and onFailureFn are optional callback functions where you can further customize the response

//create a new ModelName record
var record = new ModelName();

//update that record
record.someAttr = 'someValue';
record.$save();

//or if you prefer to submit your data in a different way
ModelName.save({
    id : record.id
  },{
  somePostObject : {
    attr1 : 'value',
    attr2 : 'value2'
  }
});

//destroy the record (and include a token)
record.destroy({ token : record.token });

Directives

Angular directives are tiny behavioural hooks that link your HTML to your plugins and to any isolated blocks of code within your application. They're designed not to change the logic of the controllers or models, but to aid in the construction of the webpage. Therefore, they're perfect for plugins, validations, dynamic text properties(such as internationalization-related and localization-related tweaks). Here's how to use them.
First define the directive within your application javascript:
angular.directive('myDirective',function($compile) {
  return {
    templateUrl : '/path/to/some/template.html', //(optional) the contents of this template can be downloaded and constructed into the element
    replace : true, //whether or not to replace the inner data within the element
    link : function($scope, $element, attributes) { //this is where your magic happens
      $scope.title = '...';
    }
  };
});
Now when angular comes a HTML tag that contains data-my-directive as an attribute (with or without a value) then it will download the template and execute the link function. You can also define the template htmldirectly and you can also create your own compile function which does all the work in one go. The $scopevariable provided within the link function is the scope variable of the controller that contains the directive. This is a powerful way to share data between the controller and the directive as well as for them to communicate between each other.

Filters

Filters are reusable operations that can be embedded directly into binding operations to tweak the data in some way. Some examples would include paginationlanguage-tweakingrole and session-specific data filtering.
App.filter('myUppercase', function(data) {
  for(var i=0; i < data.length; i++) {
    data[i].title = data[i].title.toUpperCase();
  }
  return data;
});
This filter then can be used within an angular expression:
data-ng-repeat="for record in records | filter:myUppercase">...
Or it can be used directly within your JavaScript code with the $filter function.
//be sure to inject the $filter object
var values = ['one','two','three'];
values = $filter('myUppercase')(values);

HTML5 Mode

HTML5 Mode allows for your angular app to use HTML5 history within its routing system and then gracefully degrade its functionality to hashbang support if the browser doesn't support HTML5 history. The following snippet of code enables HTML5 history within your angular application (it's disabled by default).
App.config(['$locationProvider', function($location) {
  $location.html5Mode(true); //now there won't be a hashbang within URLs for browers that support HTML5 history
}]);

Using Angular with other JavaScript frameworks/libraries

Angular states that it plays nicely with other frameworks (and it does), but angular itself has a bit of a bias towards JQuery (just as everything out on the internet does) so you may need to hack it a bit to get it to work with something other than JQuery. Angular uses JQLite to do its basic DOM handling and doesn't fully rely on JQuery.

Using Angular with JQuery

JQuery works fine with Angular. Just include it before you include angular into your web application and angular will use your JQuery include instead of JQLite.

Using Angular with MooTools

MooTools also works fine, but there are some problems when accessing elements. You will need to create your own dollar-style selector (or override the existing one). Also, be sure to include MooTools into your web application after angular has been included.
var $moo = function(element) {
  if(typeOf(element) != 'element' && element.length >= 1) {
    element = element[0];
  };
  if(element) {
    return document.id(element);
  }
};
This should make angular work MooTools; just be sure to use the $moo method each time before accessing an element which has been provided by a controller or directive in angula. The double dollar function ($$) isn't affected, but call the $moo method before you use the $$ to access an element directly (since an element provided from angular may be an array and that may mess things up).

Using .json as a URL suffix for model operations

Angular, at the time of this writing, doesn't support customizing resource suffixes (URL formats or extensions) directly via its API. To setup it yourself you will need to hack the code within the angular-resource.js file and this is not really the best approach to fixing this. For now its not supported in angular, however, there exists a fork of angular on yearofmoo that includes support for this fix.

Going Forward

Angular is huge. There's alot that's not covered here. Now you should be well prepared to build a functional angular application. Take a visit to the angular website to find more information of what's covered here and any other of the other features that angular provides.
Please share or bookmark this article.

3 comments:

oakleyses said...

jordan pas cher, chanel handbags, nike outlet, michael kors pas cher, kate spade outlet, replica watches, longchamp pas cher, nike free, jordan shoes, christian louboutin shoes, nike free run, louis vuitton outlet, oakley sunglasses, ray ban sunglasses, polo ralph lauren, ugg boots, christian louboutin uk, air max, louis vuitton outlet, ugg boots, tiffany jewelry, polo ralph lauren outlet online, burberry pas cher, prada outlet, nike air max, gucci handbags, sac longchamp pas cher, ray ban sunglasses, louboutin pas cher, louis vuitton, uggs on sale, tiffany and co, oakley sunglasses, louis vuitton outlet, ray ban sunglasses, longchamp outlet, louis vuitton, longchamp outlet, replica watches, nike roshe, polo outlet, oakley sunglasses, cheap oakley sunglasses, oakley sunglasses wholesale, christian louboutin, christian louboutin outlet, tory burch outlet

oakleyses said...

lululemon canada, nike air max, burberry outlet, oakley pas cher, burberry handbags, coach outlet store online, kate spade, michael kors outlet, michael kors, nike air force, true religion jeans, true religion outlet, michael kors, polo lacoste, nike tn, new balance, abercrombie and fitch uk, michael kors outlet, uggs outlet, michael kors outlet, ralph lauren uk, michael kors outlet online, replica handbags, coach outlet, true religion outlet, coach purses, nike free uk, sac vanessa bruno, mulberry uk, michael kors outlet online, michael kors outlet online, michael kors outlet online, north face, uggs outlet, converse pas cher, hogan outlet, nike air max uk, hollister pas cher, sac hermes, nike roshe run uk, hollister uk, nike air max uk, true religion outlet, timberland pas cher, vans pas cher, ray ban pas cher, guess pas cher, ray ban uk

oakleyses said...

supra shoes, marc jacobs, canada goose, converse outlet, toms shoes, ugg uk, ugg pas cher, canada goose outlet, canada goose, nike air max, louis vuitton, karen millen uk, doudoune moncler, converse, louis vuitton, vans, gucci, montre pas cher, moncler outlet, canada goose uk, canada goose outlet, moncler, pandora jewelry, barbour uk, moncler outlet, juicy couture outlet, louis vuitton, canada goose, pandora uk, coach outlet, swarovski crystal, ugg,uggs,uggs canada, juicy couture outlet, links of london, louis vuitton, louis vuitton, hollister, swarovski, canada goose outlet, ray ban, moncler, ugg, barbour, ugg,ugg australia,ugg italia, replica watches, pandora charms, moncler uk, pandora jewelry, wedding dresses, canada goose jackets, hollister, lancel