~ About 10 minutes read.

Index

  1. MVC, SPA and two-way data binding
  2. Directives
  3. Filters and expressions
  4. Scope, controllers and DI
  5. Services
  6. Useful links

MVC, SPA and two-way data binding

Angular.js is a Google-maintained JS framework. Those are the three main features which ensure its fame: * MVC pattern support * Two-way data binding support * SPA compliant

MVC

MVC stands for Model View Controller and it's a pattern, a way of working. It consist in logically dividing an application in various components, ensuring it is easy to mantain, to update and to scale. The view is basically the HTML page shown to the end user, the model is the data displayed in the view and the controller is a component in charge of how the two interact with each other.

Two-way data binding

View and model data are linked together and, thanks to the two-way data binding, an update to the view gets propagated to the model and vice versa. That's why the data binding is "two-way", because data updates flow both from the view to the model and the other way around. This mechanism, however, is expensive on a resources level. Internally, Angular assigns a listener(watch) to every variable declared and, every time an event is triggered, it looks for changes in stored values. If it can find one, Angular updates the variable and saves the new reference. This process is referred to as "dirty checking" and it gets executed during the dygest cycle, when Angular updates the saved values.

Furthermore, this problem influences also event handling. Before calling the function associated with the listener of the triggered event, Angular checks which model value has changed, and then calls the corresponding listener. A small delay is introduced, compared to the native JS way of handling events, where the listener is immediately called, once the event and the DOM node that triggered it are located.

SPA

SPA stands for Single Page Application and they replicate a website made up of a single page, in which every section is loaded only when necessary, without actually moving to another page. This is achieved using support libraries such as Angular UI Router.

More reading

Directives

Directives are Angular instructions which extends basic HTML tags capabilities. They are expressed in the "ng-directiveName" form. They can be custom HTML tags, HTML tags attributes, CSS classes or even comments, though the element and attribute ones are the most frequently used.

  <html ng-app="app1"> ... </html>

Directives are compiled by Angular which loops over the DOM looking for them. To let Angular know where to start compiling we use the ng-app directive, which marks the starting point.

  let app = angular.module('app1', []);

To then handle the business logic of our app we will need to create a module to associate the ng-app directive to, as shown above. The module() function gets passed the module name and an array of dependancies, which are external modules needed by the current module. The ng-app attribute value needs to match the name of the module for the two to be bound.

Custom directives

  app.directive('myCustomer', function() {
    return {
        restrict: 'A',
        template: 'Name: Davide, Surname: Vico'
    }
});

Each directive is registered inside Angular's source code, where it gets declared and set up, so that Angular knows how to interpret it once found in the DOM. We can also create custom directives, following the above structure. Using the directive() function a myCustomer directive is created and bound to the app module, which has to be previously declared. The function passed to directive() returns an object which holds the directive properties. The restrict property states what kind of directive we are creating( in this case it's an HTML attribute ), while the template one sets the text to be shown inside the directive. We can also inject an external HTML file, called partial using the templateUrl property, setting it to the URL of the partial to load.

More reading

Filters and expressions

Expressions

Expressions are instructions which aim to display dinamic code inside HTML pages.

  4 + 4 = {{ 4 + 4 }}

Epressions are enclosed in double curly braces, as shown in figure above, and with them we can display variables or calculations' result. The result displayed will be 4 + 4 = 8.

Filters

Filters are added to expressions, or also to directives, to, well, filter the result, or format it.

  4 + 4 = {{ 4 + 4 | number:2 }}

Filters are applied after an expression, with a pipe character separating the two. The number filter casts the result to a number. If the result can't be converted to a number, then there will be no output rendered, whereas if we don't put a filter NaN is shown. After the colon we pass parameters to the filter. The number filter receives the number of decimals the output value will have.

Custom filters

  app.filter('myFilter', function() {
    return function( input ) {
        return input ? 'someValue' : 'someOtherValue';
    }
});

Custom filters are available and they have to be declared, just as with directives. In the example a filter1 filter is declared and bound to the app module. The filter() function receives a function that will handle the internal logic. This function returns another function, which in turn receives the value of the expression/directive the filter is applied to("input", in this case). This last function returns the formatted output.

More reading

Scope, controllers and DI

Scope

The scope is an object which holds the data related to a specific portion of the application. The meaning behind the scope object is the same as the scope of a variable, but in Angular it's a physical object, accessible through the $scope service(we will be discussing services shortly). Angular internal objects are prefixed with a dollar symbol, to distinguish them from custom objects. Therefore, it is good practice not to use dollar signs in custom objects' names.

Controllers

  <body ng-controller="ctrl1"> ... </body>

If we were to set an initial value to a variable, or to perform more advanced actions we need to bind the app portion in which we use them to a controller, as shown above. We now have bound the body tag to a ctrl1 controller using the ng-controller directive, so that every variable created or updated inside the body tag is stored in the ctrl1 controller's scope. To every controller instance corresponds a scope, so if we use the same controller multiple times on the same page we will have more instances of the same scope. From inside the controller we can access the scope variables through the $scope.property syntax. When there is no controller explicitly declared on the page, expression values and variables are assigned to the global scope.

  app.controller('ctrl1', function( $scope ) {
    ... 
})

To use the controller inside the HTML we need to declare it, just as we do with directives. The ctrl1 controller is now bound to the app module. The controller() function receives the name of the controller and a function in which we can update or create variables bound to the controller's scope. This function receives as paramethers a list of dependancies, the only required one is the $scope service.

Dependancy injection

The aforementioned $scope instance gets passed by Angular through the so-called "Dependancy Injection". What it does is it provides the required dependancies, locating their instances by interpreting the HTML tag the controller is bound to, in order to determine the right object to pass in. For instance, in the example above, Angular compiles the ng-controller directive on the body tag it figures out that the variables used inside the body tag are the ones defined in the scope of the ctrl1 controller.

More reading

Services

You can think of services like containers of functionalities related to a specific matter, kind of like classes. Examples include $timeout, to perform timing-related operations, just as JS' setTimeout and setInterval, or $watch, which allows to set up an event listener on a scope property, that waits for changes to the said value and fires an event when that happens. As an alternative to services we can also use factories or providers, which roughly provide the same features, and so, for the purposes of this post, won't be covered.

Custom services

  let srvc = angular.module('srvc', []);

srvc.factory('srvcExample', function() {
    let self = {};

    self.foo = function() {
        ... 
    };

    return self;
});

In the figure above we are declaring an srvcExample factory, bound to the srvc module. The function we pass to the factory() function its used to set up the factory. This function will return an instance of the factory, which is a singleton object, meaning that every time the srvcExample gets used the same instance is accessed. This is especially useful when sharing data between controllers. A common use case would be of a controller storing data in a service making it available to other controllers as well.

  let app = angular.module('app1', ['srvc']);

We can access services' methods from inside controllers. To do so, we declare the service in the dependancies array of the module the controller is bound to, by adding the service module name as shown above.

  app.controller('ctrl1', function($scope, srvcExample));

All we need to do now is pass to the controller's function the name of the service we want to make available to the controller.

More reading

More great resources

These are two links I used when learning Angular for the first time. The first one is of a website with interactive and challenging exercises. The second one is of a YouTube playlist created by YouTuber Derek Banas. They are full of examples and perfectly explained, I learned a lot just from following that playlist.


855 0 14