cri.dev
about posts rss

Introduction to AngularJS

Published on
Tagged with angularjs10

Angular is a JavaScript framework for creating modern web applications,
which are inherently declarative, modular, with testability in mind.

Angular brings along its great ecosystem of modules and third party libraries,
a templating engine for view manipulations, a modules concept, XHR/AJAX library,
slimmed down Promises and jqlite implementations, and much, much more.

Table of contents

Modules

Modules are Angular`s way of grouping user defined services.
Modules can require other modules and are resolved asynchronously without
worrying about execution order etc. Your service will be instanciated when all
its collaborators/dependencies are loaded.

For example here I`m defining tiny namespaced modules that I can require in others:

angular.module('app.modules.auth',[])
angular.module('app.modules',['app.modules.auth'])
angular.module('app.controllers',[])

angular.module('app',[
  'app.modules',
  'app.controllers',
  'ui.router' // third party dependency
])

ng-app and Angular startup phase

Defines the namespace (scope) of an Angular application.
Note: a page can contain multiple Angular application, although they cannot be not nested

ng-app is a so called directive, which we will later talk about what it means.
The ng-app directive registers the Angular application scope and starts the application
configuration and run phase.

Imagine you have the following markup that represent your single page application written in Angular:

<!DOCTYPE html>
<html lang="en" ng-app="app">
  <head>
    <meta charset="UTF-8">
    <title>Document</title>
  </head>
  <body>

  </body>
</html>

You can see that the page contains the ng-app directive on the html element,
so the whole page is the scope of our Angular application.

The corresponding JavaScript to define the application:

angular.module('app',[])
angular.module('app').config(function(){ /*config phase*/ })
angular.module('app').run(function(){ /*run phase*/ })

This is everything you need to wire app your Angular application. From here we can iterate.

data-binding and the digest loop

Angular adopted the concept called “data-binding”.
Put simply it means:

  • you declare in your views what you want to be displayed
  • in your model you have the data that needs to be displayed
  • both are kept in sync (user input changes the model, and model updates change the view)

Model and View are kept in sync via a mechanism called “dirty checking”, and in Angular this dirty work
is handled by the digest loop.

Provider, Factory, Service, Value and Constant

Application services in Angular are defined by registering them in a module. The registration (and later injection)
is done by the injector, and follows a recipe to create them.

You can define what “type” of Application service you want to define, there is one (+3 with syntactic sugar):

The provider

It is used for application wide configuration of a later injectable service.
You can register a provider like this:

module.provider('Logger', function(){
  var enabled = true
  this.enable = function(_enabled){enabled = !!_enabled}
  this.$get = function(){
    return new Logger(enabled)
  }

  function Logger(enabled){/*...*/}
})

The factory

Creates an injectable service which returns the value it has been instructed to:

module.factory('MyFactory', function(){
  return new Factory()
})

The service

You will be provided by an instance of the function:

module.service('MyService', function(){
})

The value and constant

Returns the value. The difference between the two is that a constant can only be injected
during the configuration phase and in providers. The value can be injected expect in those cases.

module.value('MyValue', 42)
module.constant('MyValue', 42)

Directives

Angular directives have been introduced to create new semantically meaningful components with custom behaviour, or augmenting
behaviour of existing tags.

An example I like to make is the <profile> component.

module.directive('profile', function(){
  return {
    restrict: 'EA',
    template: 'profile.html',
    controller: function($scope, AuthService){
      /* display profile if authenticated, hide if not authenticated.. */
    }
  }
})

We introduced a <profile> component that is easily testable in isolation and does one thing very well,
showing the currently logged in user.

As we said a directive can also be used to introduce custom behaviour on an element.
Lets take a look at some directives Angular ships with, for exampleng-click`:

<span ng-click="click()">click me</span>

As you might expect with this directive a function click() is called when the element is clicked,
nothing surprising but extremely powerful. Think about analytics tracking, communication between components,
custom behaviour, input validation, etc…

Filters

Filters are used to format and apply transformations to user input.
Some example are currency, json formatting, etc.

module.filter('camelCase', function(){
  return function( input ){
    if( !input ) return input
    return input[0].toUpperCase() + input.substr(1)
  }
})

Interceptors

Interceptors operate at the http request/response level. You could use them for
Authorization handling, logging, error handling, etc.

module.factory('AuthHeaderInterceptor', function(token){
  return {
    request: function(config){
      config.headers.Authorization = 'Bearer ' + token
      return config
    })
  }
})

angular-start

To conclude this article I reccommend you to check out my repo to start a new Angular project from scratch!
It includes testing framework already setup with examples and basic structure to get going fast

Here, have a slice of pizza 🍕