AngularJS 1.x - rohit120582sharma/Documentation GitHub Wiki

MVC

Model-View-Controller is a design pattern to organize the code to make it modular, reusable, readable, and easy testable. It promotes loose coupling between components by separating the functionality of displaying and maintaining of the data. The core idea is that you have clear separation in code between managing its data, application logic and presenting data to user.

In other terms, MVC is a way of developing apps by keeping the data (model) used in the program, and the visual (view) component separate from one another, each interacting only with a controller containing the logic. The view and the model interact only with the controller NEVER with each other.

html

Model

A model represents the core business logic and state

  • Manages the app data and state
  • Not concerned with UI or presentation
  • Often persists somewhere
  • Same model should be reusable, unchanged in different interfaces

View

A view renders the contents of a model. A view accesses the data from the model and adds display logic to present the data.

  • Present the Model to the user in an appropriate interface
  • Allows user to manipulate data
  • Does not store any data
  • Easily reusable & configurable to display different data

Controller

A controller acts as the glue between a model and a view. A controller translates interactions with the view into actions to be performed by the model.

  • Intermediary between Model & View
  • Updates the view when the model changes
  • Updates the model when the user manipulates the view

Dependency Injection

Each web application you build is composed of objects that collaborate to get stuff done. These objects need to be instantiated and wired together for the app to work. Dependency Injection is a software design pattern in which components are given their dependencies instead of hard coding them within the component.

AngularJS DI

  • In AngularJS apps most of these objects are instantiated and wired together automatically by the injector service.
  • $injector is used to retrieve object instances as defined by provider, instantiate types, invoke methods, and load modules.
  • The $provide service has a number of methods for registering components with the $injector.
  • Angular provides following core components which can be injected into each other as dependencies:
    • constant: constants are used to pass values at config phase considering the fact that value can not be used to be passed during config phase.
    • provider: provider is used by AngularJS internally to create services, factory etc. during config phase(phase during which AngularJS bootstraps itself).
    • service: service is a singleton javascript object containing a set of functions to perform certain tasks and can be injected into controllers or other services.
    • factory: factory is a function which is used to return value. It creates value on demand whenever a service or controller requires. It normally uses a factory function to calculate and return the value.
    • value: value is simple javascript object and it is used to pass values to controller during config phase.

$injector service

  • Each AngularJS application has a single $injector that gets created when the application first starts.
  • The injector is responsible for actually creating instances of components like services, factory, and controller etc. by invoking functions via the $injector service.
  • There are two ways of annotating these functions so that the injector knows what services to inject into the functions:
  • Inline Array Annotation
    someModule.controller('MyController', ['$scope', 'greeter', function($scope, greeter) {
        // ...
    }]);
  • $inject Property Annotation
    var MyController = function($scope, greeter) {
        // ...
    }
    MyController.$inject = ['$scope', 'greeter'];
    someModule.controller('MyController', MyController);

Module

Introduction

  • Modules are AngularJS highest level organisational unit.
  • Module is like a package to group the relevant code for the application under a single name.
  • Module is used to keep the code out of global namespace to avoid code confliction.
  • Module is a collection of configuration and run blocks which get applied to the application during the bootstrap process.
  • Module can define components like controllers, services, directives, and filters. These are JavaScript functions to perform task.
  • Module can list other modules as dependencies, which enables to include components from another module in your module.
  • Module is defined by angular.module('moduleName', []) method.
  • To inform Angular which modules needs to bootstrapped as starting point of the app, we use ng-app directive on a DOM element

Bootstrap process

Depending modules are loaded before the requiring module. Applies all constant definitions.

Constant

A constant is a simple JavaScript object. It is created just once, so constant is a singleton. Constant can’t contain private members. All members of a constant are public.

angular
.module(“myModule”)
.constant(“sampleConstant”, {
	pi: Math.PI
});

Value

A value is also like a constant. The difference is, a constant can be injected into config blocks, but a value cannot be injected.

angular
.module(“myModule”)
.value(“sampleValue”, {
	cities: [“New Delhi”, “Mumbai”, “Kolkata”, “Chennai”],
	addCity: function(city){
		cities.push(city);
	},
	getCities: function(){
		return cities;
	}
});

Configuration blocks

Config block runs as soon as a module is loaded. It is the code which is executed during the provider registrations and configuration phase. As the name itself suggests, the config block is used to configure the application. Services, Factories and values are not available for config block as they are not created by this time. Only providers and constants are accessible inside the config block. Config block is executed only once in the lifetime of an Angular application.

angular.module(“myModule”).config(function(samplePrdProvider, sampleConstant){
	samplePrdProvider.init();
	console.log(sampleConstant.pi);
});

Run blocks

Run block is used to initialize certain values for further use, register global events and anything that needs to run at the beginning of the application. Run block is executed after config block, and it gets access to services, values and factories. Run block is executed only once in the lifetime of an Angular application.

angular.module(“myModule”).run(function(<any services, factories>){
	console.log(“Application is configured. Now inside run
	block”);
});

Service

Purpose

  • They are responsible for fetching, storing, and processing data from remote servers
  • Controllers get created and destroyed. If we need state stored across application, it belongs in a service
  • Services are a perfect tool for exposing data loaded from the server because services are singletons
  • Services are registered with the dependency injector and they are wired together by AngularJS’s dependency injector outside the scope hierarchy

Unique

  • A service is instantiated at most once, and the instance is shared among all controllers, services, and directives that depend on that service
  • A service cannot list a local as a dependency like $scope

Share data between services

Services depending on other services

  • The most basic tool for communicating between services is that one service can list other services as dependencies

Service Event Emitter Module

  • The event‐emitter module is scope‐independent, so it is ideal for use in services that don’t have access to scopes
  • The functions you interact with are named .on() and .emit(). These correspond to .$on() and .$emit() on AngularJS scopes
    // Service Event Emitter Module
    var app = angular.module('app', []);
    app.factory('userService', function($timeout, $window) {
        var emitter = $window.emitter();
        var user = {};
        $timeout(function() {
            // Simulate an HTTP error
            user.emit('error', 'Could not connect to server');
        }, 2000);
        ['on', 'once', 'emit'].forEach(function(fn) {
            user[fn] = function() {
                emitter[fn].apply(emitter, arguments);
            };
        });
        return user;
    });
    app.factory('profileService', function(userService) {
        var ret = {
            user: userService,
            isValid: function() {
                return ret.user && ret.user.name;
            }
        };
        userService.on('error', function(error) {
            ret.error = 'This is a sample error message ' +
                'that would tell the user that you can\'t ' +
                'connect to the server';
        });
        return ret;
    });
    app.controller('ProfileController', function($scope, profileService) {
        $scope.profile = profileService;
    });

Controller

Purpose

  • They are built on top of services to provide data and functionality to AngularJS's scope hierarchy
  • They are responsible for exposing data and functions to HTML
  • They are instantiated from HTML using ng-controller directive and AngularJS's dependency injector. However, controllers are not registered with the dependency injector, so controllers and services cannot list controllers as dependencies.

Unique

  • There are two unique properties of controllers relative to services
  • Each instance of the ng-controller directive creates a new instance of the controller (that is, calls the controller function).
  • Controllers can list objects called locals as dependencies. A local is a context‐specific object registered with the dependency injector for that specific instance of the controller. The most common example of a local is the $scope object.

Share data between controllers

Scope Inheritance

  • Each instance of the ng‐controller directive creates a new scope, and nested instances of the ng‐controller directive create nested scopes
  • Child scopes have access to variables and functions declared in each of their ancestor scopes
  • $rootScope: It's created on module level and it is root object in scope inheritance. Every scope object is a child object of this object in scope hierarchy
  • It is typically the wrong choice for sharing data between controllers which makes tight dependency between them

Scope Event Emitter Paradigm (Broadcasting events through $scope)

  • AngularJS scopes contain an implementation of the pervasive event emitter design pattern. This design pattern allows objects to emit/broadcast named events that then trigger the listener functions registered using the $on() function
  • The $emit() call bubbles up the scope hierarchy, so listeners registered with $on() on ancestor scopes will be triggered
  • The $broadcast() function behaves a lot like the $emit() function, except that the event propagates to descendant scopes instead of ancestor scopes

ModelService

  • For some common use cases, such as loading data from a server, it isn’t necessarily clear which controller should be responsible for querying the server and generating an event
  • Services are a perfect tool for exposing data loaded from the server because services are singletons
  • Services are accessed through the AngularJS dependency injector

Data Binding

Purpose

Data-binding in Angular apps is the automatic synchronization of data between model and view components. It allows you to tie your view to your model directly from your HTML using directives. Your model will consist of simple strings, numbers, and other primitive JavaScript types. Using data binding, your view defines how to render the model.

In general, directives fall into three classes in terms of their interaction with data binding:

  • ngBind is a directive that creates a one‐way data binding. It only renders data
  • ngModel is a directive that creates a two‐way data binding between the input field and the variable-name. It renders data and modify data as well
  • ngClick is a directive that wraps event handlers which may call some task and modify the data. It can't render data

Scope

A scope is an object to store JavaScript data and functions to expose into DOM. A scope object is created for each instance of the ng-controller which can list it as dependencies using $scope.

Scope into DOM - AngularJS expressions

  • An expression is a string containing JavaScript code that’s meant to be evaluated by AngularJS
  • A scope is an execution context for AngularJS expressions into the DOM
  • AngularJS parses these expressions and evaluates them against the associated scope

Scope Inheritance

In scope inheritance, ngModel can read variables from its parent scopes. But it can only assign to its current scope, AngularJS won’t let it assign a value to a parent scope. Functions on the global window object cannot be accessed from within AngularJS expressions

Scope methods/functions

Scopes have three important functions that are fundamental to the way data binding works:

  • $watch
    • It enables you to set a callback function to be called whenever the value of a given expression changes
    • The callback function is often referred to as a watcher
    • Each scope maintains a list of watchers, called $scope.$$watchers. $watch simply adds a new watcher
  • $apply
    • It informs AngularJS that something has changed and the values of $watch expressions should be recomputed
    • Internally, it calls $rootScope.$digest()
  • $digest
    • $digest evaluates all the $watch expressions in a scope, as well as the scope’s children, and fires the watcher callback on any that have changed

Filter

Filters are chainable functions that are accessible from any AngularJS expression. They are usually used for last‐second data post‐processing before the data is rendered. Filters tie in to data binding in a one‐way manner, so you can use filters with directives like ngBind and ngClick, but not directives like ngModel.

There are three common use cases for filters:

  • Transforming data
  • Wrappers for Global Functions
  • Manipulating Arrays

Server Communication

REST API

It stands for Representational State Transfer, is a paradigm for designing APIs that are accessed via HTTP using methods to describe specific actions on resources. Using the POST method tells the server to create a resource, GET to read an existing resource, PUT to update an existing resource, and DELETE to delete an existing resource.

Promises

JavaScript HTTP requests are asynchronous, means code that makes an HTTP request continues executing without waiting for the server to return a response. Promises provide a convenient alternative to callbacks or event emitters for handling asynchronous functions.

  • A promise is an object‐oriented construct for dealing with asynchronous operations.
  • It is an object representing a value to be computed at some point in the future.
  • The core feature of promises is the then() function which takes two function parameters: onFulfilled and onRejected.
  • Promises can be in one of three states: pending, fulfilled, or rejected. A promise starts out in the pending state and then can transition to the fulfilled or rejected state.
  • Once a promise is fulfilled or rejected, it can’t change state.
  • If an onFulfilled function is attached after the promise is already fulfilled, that onFulfilled function will be called.

Services for HTTP requests

AngularJS has two services that wrap the native browser XMLHttpRequest class: $http and $resource.

$http

  • Introduction
    • The $http service is low‐level wrapper around native browser HTTP requests.
    • The $http service of AngularJS allows us to communicate with a backend and make HTTP requests.
    • The $http service exposes several functions/methods corresponding to the GET, HEAD, POST, PUT, DELETE, or PATCH HTTP methods that make a new request with the given method.
    • These functions return a promise wrapper around the HTTP response from the server, which you use to capture the data that the server returns.
    • The $http service automatically parses the JSON into a JavaScript object.
  • JSONP and Cross Site Scripting (XSS)
    • Modern browsers has security restriction not allowing to make HTTP requests to different domains.
    • JSONP is a method for sending JSON data without worrying about cross-domain issues.
    • It does not use the XMLHttpRequest object. It uses the <script> tag instead.
    • AngularJS’s $http.jsonp function abstracts out the client‐side code for implementing JSONP.
    • The remote server must be configured to support JSONP
  • HTTP Interceptors
    • An interceptor is simply a regular service factory which has request, requestError, response, or responseError methods defined on it to intercept each HTTP calls.
    • An intercept is registered with the $httpProvider by adding them to the $httpProvider.interceptors array which activates it.
    • HTTP Interceptors executes some custom logic before or after the HTTP call.
    • HTTP interceptors are used for adding custom logic for authentication, authorization, session/state management, logging, modifying Response, URL rewriting, Error handling, Caching, adding custom header, timestamp in the request/response, encrypt and decrypt the request and response information or manipulate the request and response data over the request cycles.
    • request method: This interceptor is called before $http sends the request to the server. This function takes the request configuration object as input parameter and returns a configuration object. A common use case for request interceptors is setting an HTTP authorization header for each request.
    • response method: This interceptor is called when the $http receives the response from the server. This function receives a response object as a parameter return a response object or a promise. response interceptor is used to modify the response data or adding a new set of values, calling another module or services call.
    • responseError method: The application level generic error handling is achieved by using this interceptor. There are some situations where one call has failed and the application need to trigger some action based on different HTTP status code. The responseError function interacts with promise using $q service rather than with response directly. A common use case for responseError interceptors is recovering the session and resending the original request again automatically for situations where the session expired.
angular
    .module('myApp', [])
    .factory('httpInterceptor', ['$log', '$q', '$window', '$injector', httpInterceptorFun])
    .config(['$httpProvider', configFun]);


function configFun($httpProvider){
    $httpProvider.interceptors.push('httpInterceptor');
    $httpProvider.defaults.useXDomain = true;
    delete $httpProvider.defaults.headers.common['X-Requested-With'];
}

function httpInterceptorFun($log, $q, $window, $injector){
    var service = {};
        service.request = requestHandler;
        service.response = responseHandler;
        service.requestError = requestErrorHandler;
        service.responseError = responseErrorHandler;
    return service;
    
    /*
    *
    * @Description
    *		-> Process HTTP request at the application level
    *		-> Config Authorization Header by setting session credential (access-token) to send to server with every HTTP request
    *
    */
    function requestHandler(config){
        if($window.localStorage.accessToken){
            config.headers.authorization = 'Bearer ' + $window.localStorage.accessToken;
        }
        return config;
    }
    function responseHandler(response){
        return response;
    }
    function requestErrorHandler(config){
        return $q.reject(config);
    }
    /*
    *
    * @Description
    *		-> Process HTTP response-error at the application level
    *		-> Session Recoverer (where the session gets lost/expire)
    *
    */
    function responseErrorHandler(response){
        if(response.status === 400 || response.status === 401 || response.status === 403 || response.status === 419){
            var SessionService = $injector.get('SessionService');
            var $http = $injector.get('$http');
            var deferred = $q.defer();

            // Create a new session (recover the session)
            // We use login method that logs the user in using the current credentials and returns a promise
            SessionService.login().then(deferred.resolve, deferred.reject);

            // When the session recovered, make the same backend call again and chain the request
            return deferred.promise.then(function(){
                return $http(response.config);
            });
         }
        return $q.reject(response);
    }
}

$resource

  • The $resource is a factory that lets you interact with RESTful backends easily.
  • The $resource service allows you to create a convenient wrapper around a REST API enabling you to perform CRUD operations without directly creating HTTP requests.
  • The $resource service is not part of the AngularJS core. To use it, you must include the angular-resource.js file and add a dependency on the ngResource module.
  • The $resource service expects a classic RESTful backend. This service needs to be declared as a dependency inside controller/service.
  • Calling $resource() function with REST endpoint returns a $resource object which has five methods (get, query, save, delete, remove) to interact with the REST backend.
    angular
        .module('movieApp.services', [])
        .factory('Movie', ['$resource', function($resource){
            return $resource('/api/movies/:id', {id:'@_id'}, {
                update: {
                    method: 'PUT'
                }
            });
        }])
        .controller('MovieListController', ['$scope', '$state', '$stateParams', 'Movie', function($scope, $state, $stateParams, Movie){
            /* Get list of all movies */
            $scope.movies = Movie.query();
            /* Delete a specific movie */
            $scope.deleteMovie = function(movie){
                movie.$delete(function(){
                    $window.location.href=''; // $scope.movies = Movie.query();
                });
            }
        }])
        .controller('MovieViewController', ['$scope', '$state', '$stateParams', 'Movie', function($scope, $state, $stateParams, Movie){
            /* Variables */
            var movieID = $stateParams.id; // 123
            /* Get detail about a specific movie */
            $scope.movie = Movie.get({id:movieID});
        }])
        .controller('MovieCreateController', ['$scope', '$state', '$stateParams', 'Movie', function($scope, $state, $stateParams, Movie){
            /* Create a new movie */
            $scope.movie = new Movie();
            $scope.addMovie = function(){
                $scope.movie.$save(function(){
                    $window.location.href='';
                });
            }
        }])
        .controller('MovieEditController', ['$scope', '$state', '$stateParams', 'Movie', function($scope, $state, $stateParams, Movie){
            /* Variables */
            var movieID = $stateParams.id; // 123
            /* Get detail about a specific movie */
            $scope.movie = Movie.get({id:movieID});
            /* Update a movie */
            $scope.updateMovie = function(){
                $scope.movie.$update(function(){
                    $state.go('movies');
                });
            };
        }]);

Routing

The general idea behind an SPA in AngularJS is that modify the hash portion of the URL rather than linking to a new page.

Deep linking

  • The hash portion/tag is typically used for deep linking functionality. For ex:- http://www.google.com/foo?bar=baz#qux.
  • The path (/foo) and query string (?bar=baz) communicate to the server for the precise resource which means changing the path or the query string triggers a page reload.
  • Whereas, the browser does not send the hash portion to the server; thus, the hash component can be modified without triggering a page reload.

AngularJS’s templating system

AngularJS templates bring the notion of including external HTML into your page to the client side. The ngInclude directive is the simplest way to utilize client‐side templating. This directive replaces the associated DOM element’s inner HTML with a given template’s HTML. AngularJS templates are static HTML, they can be cached by the browser, leading to reduced bandwidth usage and better performance.

$location

$location service provides a convenient interface for reading and modifying the current URL (hash portion) without reloading the page. The $location service exposes four important functions: url(), path(), search(), and hash() to operate on the hash portion of the URL. You cannot use the $location service to redirect your user to an entirely new page.

Routing

  • Introduction
    • The term routing in web development means mapping the path portion of a hash pseudo‐URL to a handler for that particular route.
    • In AngularJS, a route handler is typically an object that defines the template URL that should be rendered and the controller for the template.
⚠️ **GitHub.com Fallback** ⚠️