Angular tutorial

Angular is one of the first major MVC frameworks entirely written in JavaScript targeted to run on the browser. Although web applications have long used the MVC design pattern [1], up until Angular's appearance, the use of MVC in web applications was constrained to server-side programming and languages like Python, PHP, Ruby and Java.

Angular emerged as a solution for SPA (Single Page Applications). The principle of SPA is to unify the functionality of multiple web pages -- dozens or hundreds -- into what's behaviorally a single page, creating a more fluid user experience -- like a desktop application -- instead of transitioning from one web page to another which requires full page refreshes. Inevitably, SPA require that this single page fulfill a lot more duties than an ordinary web page, in a language that's natively understood by web browers (i.e. JavaScript).

To get an initial idea of what SPA and Angular must fulfill in terms of additional duties, let's re-cap some of the high-level tasks involved in developing a web application using the MVC design pattern with a server-side language like Python, PHP, Ruby or Java.

  • You create a controller (in Python,PHP,Ruby,Java) to process requests for various web page URLs (e.g. homepage, profile, items).
  • Inside a controller you can manipulate or enrich a request's data to satisfy business requirements. To manipulate/enrich requests you'll import libraries (in Python,PHP,Ruby,Java) to avoid having to write complex logic from scratch (e.g. parsing text, mathematical calculations). If the manipulation/enrichment process is common enough, you can even export your own library (in Python,PHP,Ruby,Java) for use on multiple controller locations or in different projects.
  • Once a controller is done manipulating or enriching a request's data for a given URL it sends everything to a view. A view is a boilerplate file with HTML and placeholders (in Python,PHP,Ruby,Java) that gets substituted with a request's data.
  • When the view is finished, the controller sends a response -- which is what the view generates -- back to the party that originated the request.

The terms may vary a little depending on the server-side technology, but this last sequence is what happens to a greater extent on all server bound web applications that use the MVC design pattern. Now envision this same sequence of events all taking place on an end user's browser. This is what Angular helps you achieve.

Angular is now in its fourth major version and has very agressive releases with major versions scheduled every six months (e.g. Version 4 release in March 2017, version 5 release in October 2017, version 6 release in March 2018). Conceptually only Angular 1 is substantially different than other releases, while remaining Angular releases (e.g. Angular 2, Angular 4, Angular 5) are more similar between one another, to the point new Angular releases are simply referred to as Angular. So when I say Angular from this point on, I'll be talking about core concepts applicable to Angular 2 versions and beyond, unless otherwise noted.

Angular & its languages: JavaScript is dead, long live JavaScript or TypeScript or is it Dart ?

If first impressions count for programming languages, then JavaScript probably ranks as one of the worst of all time. You really can't expect a lot from a programming language that was put together in 10 days[2]. Whether it was a lack of exception handling in the initial versions, its awkward approach to inheritance or its ad hoc support for modules & namespaces, JavaScript has played catch-up for over 20 years with other programming languages in terms of design and features. But for all its faults, no other language has ever scratched -- let alone threatened -- JavaScript's dominance on the browser.

And therein lies the conundrum for many frameworks like Angular designed to run entirely on the browser. On the one hand you want to leverage what a majority of browsers support and most developers know about, so as not to alienate people with a new programming language. But on the other hand you know the old programming language (i.e. JavaScript) comes with so many flaws, you need a new programming language to create more solid functionality. It turns out you can keep using JavaScript while introducing a new language that's more powerful than JavaScript. How is this achieved ? Converting the new language, of all things, into JavaScript! This process is an actual tendency in languages that produce JavaScript to make modern JavaScript development more inviting and stable [3].

With this approach, JavaScript purists can keep using JavaScript as they know it and those looking for more powerful and simpler approaches that JavaScript can't handle well (e.g. types, static checking, testing, modules) can use a new language that at the end of the day gets converted to JavaScript. In the case of Angular, one of these new languages I'm talking about is called TypeScript[4]: a typed superset of JavaScript that compiles to plain JavaScript, compatible with any browser, any host or any OS (Operating System).

It's worth mentioning that if you browse through Angular's documentation, you'll realize that in addition to TypeScript, Angular also works with/as plain JavaScript and Dart[5]. Dart while at the end of the day also gets converted to plain JavaScript -- just like TypeScript -- is to dissimilar from JavaScript. And while it's possible to use plain JavaScript to create Angular application, using JavaScript is beside the point, because all you'll end up doing is writing more verbose and harder-to-debug JavaScript that can easily be done with TypeScript. So for someone already familiar with JavaScript, TypeScript is the natural option for Angular and modern JavaScript applications.

Now that you've learned how Angular applications can be written in multiple languages that eventually get converted to JavaScript and why we'll be using TypeScript -- which is the most similar language to JavaScript, but with additional features -- let's move on to exploring Angular applications.

Angular applications

Angular is not a simple framework. As I mentioned at the start, Angular attempts to fulfill a lot of web application functionalities that are typically done on the server. So just as you might have gradually learned a server-side stack like Java/Spring, PHP/Symfony, Python/Django or Ruby/Rails, don't expect to learn everything about Angular in a few sessions.

To make what I assume is your first time using Angular as digestible as possible, I'll split this tutorial into two major parts covering the ways in which you can deploy Angular: an entirely browser-based approach only recommended for developing and testing applications, as well as a build-based approach intended to deliver optimized applications for production environments. In addition, each section is further subdivided into Angular's UI (User Interface) component functionalities and Angular's services functionalities.

Part I: Angular running TypeScript directly on the browser

Listing 1 illustrates a self-contained web page with Angular's UI (User Interface) component functionalities which is what I'll use to start this discussion. Listing 2 illustrates another Angular application that builds on the one from listing 1, but illustrates Angular's services functionalities. By keeping things in two separate Angular applications, I hope there's a smaller probability you'll feel overwhelmed or frustrated trying to understand Angular's various concepts.

In addition, listing 3 shows the equivalent web page with jQuery so you can easily compare the differences -- note this jQuery example is the same one used as a baseline to introduce previous modern JavaScript frameworks like React.

Listing 1 - Angular web page with UI component functionality (Part I)
Listing 2 - Angular web page with services functionality (Part II)
Listing 3 - jQuery web page with main feature set

If you skim through the index.html page in listing 1, you can see the web page structure is almost empty. With the exception of a lot of <script> elements to import resources, there's a JavaScript inline System. snippet -- which is part of the SystemJS module loader -- and the page's <body> tag that just has the <banner-app>Loading...</banner-app> element which is an Angular UI component.

SystemJS and Typescript

A module loader such as SystemJS has two purposes in Angular. The first reason is an Angular application has the potential to use dozens of JavaScript files/modules, so you're better off using a dedicated library to manage more than a couple of JavaScript files/modules. The second and more important reason for a module loader is it helps browsers load files/modules that aren't in JavaScript. Aren't in JavaScript ?! What do you mean ?!.

In a prior section I mentioned why we would use the TypeScript language -- a superset of JavaScript -- to create Angular applications. The thing with TypeScript is browsers don't know anything about it. TypeScript may be similar to JavaScript and get converted to JavaScript, but browsers don't know that. Therefore you need a way to convert TypeScript files/modules into JavaScript so browsers understand their meaning. This conversion process -- or as it's technically known transpiling -- is done by a module loader.

Near the top of the index.html page in listing 1 you can see we import the system.js library -- which gives us access to System. calls -- as well as the typescript.js library, which is tasked with converting TypeScript into JavaScript.

Listing 4 - SystemJS configuration

  System.config({
        transpiler: 'typescript',
        typescriptOptions: { emitDecoratorMetadata: true },
        packages: {'app': {defaultExtension: 'ts'}}
      });
  System.import('app/main')
        .then(null, console.error.bind(console));

Moving to the SystemJS calls in listing 4 -- which are part of the index.html page in listing 1 -- you can see the System.config statement defines transpiler: 'typescript' which configures the module loader to transpile files/modules from TypeScript. The additional System.config arguments configure on which packages the transpiler is used -- in this case, the app folder/package uses the transpiler with the default .ts extension -- and transpiler options are set with the typescriptOptions variable.

The System.import statement is used to load a module onto the page. In this case, 'app/main' indicates the app folder/package and the main file/module. And because the app package is defined with a default .ts extension in System.config, it means the loader will look for the TypeScript file app/main.ts, relative to index.html. The final .then(...) statement is a JavaScript promise that works to send all errors associated with the preceding module (i.e. 'app/main') to the console for debugging purposes.

I should mention doing the transpiling process on an end user's browser is not an efficient practice. The transpiling process -- particularly for production applications -- should be done as part of the development process. However, because you need to walk before you run, we'll let the end user's browser deal with transpiling for now. We've got a lot more to cover, but you just learned how to use a module loader to transpile TypeScript into JavaScript in a browser and how to load modules onto a page.

Initializing (a.k.a. bootstraping) Angular

You just read how the index.html page in listing 1 uses the System.import('app/main') to load the app/main.ts module. Listing 5 illustrates the contents of the app/main.ts file.

Listing 5 - Angular bootstrap of UI component


import {bootstrap}  from 'angular2/platform/browser';

import {Banner} from './banner.component';

bootstrap(Banner);

The first line in listing 5 imports the bootstrap function which is used to initialize Angular UI components. Notice the bootstrap function is imported with the syntax from 'angular2/platform/browser' which is a module provided by Angular's core library (i.e. <script src="...angular2.min.js">). The second line in listing 5 imports the Banner class which is the actual Angular UI component. Notice the Banner class is imported with the syntax from './banner.component', where the leading ./ indicates a relative path to the current file (i.e. app/main.ts). This means there must be a file named app/banner.components.ts with the Banner UI component -- note the .ts extension which is expected for all TypeScript modules under the app package.

Finally, the third and last line in listing 5 bootstrap(Banner) uses the two imports to say: Initialize/bootstrap the Banner UI component.

The Angular initialization or bootstraping process in listing 5 is one of the simplest you can have. As an Angular application grows, this type of file in listing 5 inevitably grows to bootstrap more UI components, as well as incorporate other general facilities required by an Angular application. However, this process is the same for all Angular applications. You bootstrap Angular UI components as a way to add them to a web page and the UI components interact with other classes that provide services and business logic.

Now that you know Angular applications are always initialized by bootstraping UI components, lets take a look at an Angular UI component.

Angular UI component structure

An Angular UI component is declared as a class and decorated with the @Component annotation to tell Angular it's a UI component. You use the class to define a component's fields & methods and the @Component annotation to configure a component's behaviors.

In the past section Angular bootstraped the Banner UI component located in the app/banner.components.ts file, listing 6 illustrates this file that shows the structure of an Angular UI component.

Listing 6 - Angular UI component


import {Component} from 'angular2/core';

@Component({
  selector: 'banner-app',
  template: `
    <div>
        <h4><button (click)="handleClick()">Click to {{isTheBannerVisible ? 'hide' : 'show'}} {{message}}</button></h4>
        <div [hidden]="!isTheBannerVisible">{{message}}</div>
    </div>
    `
})
export class Banner {

  message: string = "Angular 101!";
  isTheBannerVisible: boolean = true;
  

  handleClick(event) {
     this.isTheBannerVisible = !this.isTheBannerVisible;
  },

}

Listing 6 starts with another import statement for Component which comes from Angular's core library and is used to decorate the class (i.e. mark it as an Angular UI component). Also notice the component class is preceded with the export keyword to make it available to other modules. It's worth mentioning you should really get used to using import and export statements, they're a recurring practice that helps keep namespace and scope/visibility in check -- much like other languages (e.g. Java,PHP,Python,Ruby) require you to use similar import and export statements for the same purpose.

Now look at the Banner class and its two fields: message -- that will hold a display message -- and isBannerVisibile -- that will control the visibility of an HTML element. More importantly notice the field syntax <field_name>: <data_type> = <field_value>. This is TypeScript syntax to enforce type checked fields, something that's not possible with plain JavaScript. While you can keep using plain JavaScript (e.g. message = "Angular 101!";) -- because TypeScript is a JavaScript superset, plain JavaScript is equally valid -- type checking is one of the many programming techniques that's useful to avoid potential bugs.

In addition, the Banner class has the handleClick method, which is invoked when a click is made on an HTML element in the Angular UI component. All this last method does is change the value of the isTheBannerVisible field to its opposite boolean (e.g. if isTheBannerVisible is false, a call to handleClick changes the isTheBannerVisible field value to true, and viceversa).

Next, lets analyze the @Component annotation. Notice the @Component annotation is declared right above the Banner class, yes there are a lot of statements in curly braces {}, but the @Component's closing parenthesis () ends above the Banner class, which tells Angular the class is a UI Component. The statements between curly braces {} of @Component though are very important.

The selector field tells Angular on what web page element it should generate the UI component, which in this case corresponds to 'banner-app'. If you go back and see the index.html page in listing 1, you'll see precisely <banner-app> is the only element on the page. So this means Angular will swap out the original <banner-app>Loading...</banner-app> element on the page and replace it with the component's template: value.

The first thing to note about the template value in listing 6 is that it's mostly HTML markup, after all it will end up on a web page. The second thing to notice is the content is enclosed by backquotes or backticks (i.e. `, the character on the same key as the tilde ~, next to the 1/! on the keyboard) which is an important syntax to abide by, otherwise a component won't work. The HTML markup has a few things that have special meaning in Angular and I'll describe next.

The <button> element uses (click)="handleClick()". Angular treats parenthesis () in templates as events, so (click) is Angular's syntax to hook into an HTML element's click event. In this case, when a click is made on the <button> element, it will trigger the component's handleClick() method, which as described previously changes the component's isTheBannerVisible field.

To access a component's field value in templates, Angular uses double curly braces {{}}. In listing 6 you can see the Click to {{isTheBannerVisible ? 'hide' : 'show'}} {{message}} statement. The {{isTheBannerVisible ? 'hide' : 'show'}} snippet is a ternary operator that literally outputs hide or show depending on the component's isTheBannerVisible field value. The {{message}} snippet simply outputs the value of the component's message field value.

The last <div> element in listing 6 uses [hidden]="!isTheBannerVisible". Angular uses square brackets [] to define directives, so [hidden] tells Angular to apply the hidden directive -- which is a handy way to show/hide an HTML element -- to the <div> element. In this case, [hidden]="!isTheBannerVisible" indicates the <div> element should be hidden when the component's isTheBannerVisible negated value (i.e. !isTheBannerVisible) is true. Since isTheBannerVisible starts with true, its negated value is false, so the <div> element starts off visible. But because the component's handleClick() method -- assigned to the <button> element -- changes the isTheBannerVisible field value each time a click is made on the <button> element, Angular hides and shows the <div> thanks to the [hidden] directive.

And we're done....with part I. Go back and check out the example in listing 1 once more to ensure you understand everything we've done up to this point, otherwise you might get lost in the upcoming sections as I'll build on what we've done up to this point.

Angular templates

The Angular UI component in listing 6 uses the template: ` ` statement to declare a UI component's markup. While this is workable, it isn't a good practice to mix a component's functional logic with its markup. Angular UI components also support the templateUrl variable to define a UI component's markup in a separate file.

For example, you can use the templateUrl:'app/banner.template.html' statement to tell Angular to load a component's markup from the app/banner.template.html. Note the templateUrl value is relative to the location of the page where the component is loaded (e.g. index.html) and not where a component is declared (e.g. app/banner.component.ts). So if a component is loaded on the index.html page, it means the component's markup page should be located in app/banner.template.html relative to index.html.

In listing 2 you can see an Angular application that uses the templateUrl technique, based on the same component in listing 6.

Angular dependency injection

Dependency injection plays a big role in Angular, it's one of those concepts you really need to grasp to understand Angular's potential. Dependency injection is rooted in the world of OOP (Object Orientated Programming) and is used as a mechanism to instantiate objects that are related to one another. Dependency injection needs to be built from the ground-up into a framework, so even if you have experience with OOP, unless you've used a framework designed with dependency injection (e.g. Spring for Java, PHP-DI for PHP) you've probably never used it. But now that you know Angular uses dependency injection, let's get to the details.

Dependency injection is easiest to understand with the Hollywood principle: "Don't call us, we'll call you". Translated to OOP parlance, it means you don't need to do the instantiation of a related object to use it, the instantiation is done for you. In OOP you typically do object instantiation with the new keyword, however, this has a number of drawbacks particularly when there's a potential to work with dozens or hundreds of classes like an Angular application.

Directly instantiating a class with a syntax like new DataService() in another class leads to maintenance problems. A target class that needs a DataService instance only cares about getting an instance to do its work. But by using new DataService() you're forcing a target class to care about how to create a DataService instance, if one day the DataService() constructor changes, the target class also needs to be updated. With dependency injection this isn't an issue, an instance is injected into a target class and the target class never knows or cares how an instance is created.

Another issue with instantiating a class with a syntax like new DataService() is a new instance of the object is created every single time. The problem in this scenario boils down to re-usability. If you want to re-use an object instance multiple times (e.g. because it's a heavyweight process) you can't do it using new every time. With dependency injection this also isn't an issue, an instance can be re-used because it's injected into a target class and the target class doesn't know where or how it was created.

Now let me expand on dependency injection further with a series of class interactions that use dependency injection and the same set without dependency injection.

    Non dependency injection

  • Window needs Frame
  • Window creates Frame
  • Window calls Frame
    • Frame needs Glass
    • Frame creates Glass
    • Frame calls Glass
      • Glass needs Glue
      • Glass creates Glue
      • Glass calls Glue
        • Glue needs Brush
        • ....

    With dependency injection

  • Window needs Frame, which needs Glass, which needs Glue, which needs Brush
  • Window creates Brush
  • Window creates Glue and gives it Brush
  • Window creates Glass and gives it Glue
  • Window creates Frame and gives it Glass
  • Window calls Frame
    • Frame calls Glass
      • Glass calls Glue
        • Glue calls Brush

Notice how the creation or instantiation process for the dependency injection sequence is inverted, so instead of multiple "parent creates child" a "parent first creates its great-great grandchild, then its great grandchild,etc". This is why dependency injection is cataloged as a type of inversion of control, since the control to create instances is inverted. This inverted process works by having the dependencies of each object injected as they're needed, instead of having to manually create the dependencies, hence the term dependency injection or the Hollywood principle: "Don't call us, we'll call you".

By now you might be saying to yourself this sounds awfully complicated, conceptually it might sound like it, but in practice -- which I'll get to in a minute -- it isn't, particularly because most of the work is done by the underlying framework.

Because Angular applications are built entirely with classes -- some are UI component classes and others are service classes for things like data and validation -- even the most basic Angular applications end up with dependencies between classes. Managing these dependencies via injection is a pretty natural and comfortable fit, particularly when you can have dependencies three or four levels deep (e.g. a UI component container class, that depends on a UI component table class, that further depends on a UI component cell class). The more classes and dependencies an Angular application has, the more you'll appreciate dependency injection instantiation.

Angular services and dependency injection in practice

Turning our attention back to the Angular UI component in listing 6, you see its data is hard-coded (i.e. the component's message field is assigned the "Angular 101!" value directly in the class). This isn't too realistic, because in the real world a component is more likely to get its data from a separate service and it also isn't good practice to mix data with a UI component.

Next, let's create an Angular service to provide data to the UI component we've worked with up to this point. For the service I'll use dependency injection -- which I described in the previous section -- I'll also create the service to get data from a constant in a separate file and an AJAX service, as well as use a JavaScript promise and observable. Listing 7 illustrates the Angular service, which is also in the app/banner.service.ts file from listing 2.

Listing 7 - Angular service


import {Injectable} from 'angular2/core';
import {Http,Response} from 'angular2/http';
import {BANNER_MESSAGE} from './mock-banner';
import {Observable} from 'rxjs/Observable';
import 'rxjs/Rx';

@Injectable()
export class BannerService {
  constructor (private http: Http) {}

  getMessage() { 
     return Promise.resolve(BANNER_MESSAGE);
  }
  
  getMessageViaAjax(): Observable<string> {
    return this.http.get('https://jsonplaceholder.herokuapp.com/posts/1')
                    .map(res => res.json().title);
  }

}

The Angular service in listing 7 is declared as a class and decorated with the @Injectable() annotation. The @Injectable() annotation tells Angular the class can be used for dependency injection (e.g. BannerService can be injected into a UI component). Note class BannerService is preceded with the export keyword to make it accessible to other modules.

Now take a look at the constructor (private http: Http) {} statement in listing 7, it's the class constructor that's called when an instance of the BannerService is created. But do you know what the argument private http: Http means ? It represents an instance of Angular's Http class -- used for things like AJAX calls -- that's assigned the http reference. This is dependency injection at work. You didn't need to create an Http object instance manually or anything, all that was needed was for the class constructor to use an argument with a reference to an @Injectable class -- like Angular's Http class which is marked as @Injectable or any other service class marked with @Injectable. Angular takes care of all the other details, and in this case a BannerService instance gets access to an Http instance through the this.http reference.

If you look at the getMessageViaAjax() method in listing 7 you can see it uses a JavaScript observable, but more importantly the method has immediate access to make an AJAX call using the this.http reference injected by the constructor.

The getMessage() method in listing 7 uses a JavaScript promise and returns the value of the BANNER_MESSAGE constant. If you look toward the top of listing 7 you can see the BANNER_MESSAGE constant is imported through the import {BANNER_MESSAGE} from './mock-banner'; statement. In this case, the mock-banner.ts file contains the single statement export var BANNER_MESSAGE: string = 'Angular 101!'; which you can confirm in listing 2. This last last method isn't as interesting as the getMessageViaAjax() method, but still illustrates how you can get data from a constant in another application file.

Angular providers, component initialization and dependency injection in practice again

Now that we have an Angular service from the last section, it's time to integrate it into an Angular UI component. Listing 8 shows a modified version of the Angular UI component we created in listing 6, but this version uses the Angular service from listing 7.

Listing 8 - Angular UI with service

import {Component} from 'angular2/core';
import {BannerService} from './banner.service';
import {HTTP_PROVIDERS} from 'angular2/http';

@Component({
  selector: 'banner-app',
  templateUrl:'app/banner.template.html',
  providers: [BannerService,HTTP_PROVIDERS]
})
export class Banner implements OnInit {

  constructor(private _bannerService: BannerService) { }

  message: string;
  isTheBannerVisible: boolean = true;

  
  getMessage() {
    this._bannerService.getMessage().then(message => this.message = message);
  }
  
  ngOnInit() {
    this.getMessage();
  }

  handleClick(event) {
     this.isTheBannerVisible = !this.isTheBannerVisible;
  },

  handleAjaxButtonClick(event) {
     this._bannerService.getMessageViaAjax()
                       .subscribe(
                       message  => this.message = message);
  },
}

The first important change made to the component in listing 8 is the providers: [BannerService,HTTP_PROVIDERS] statement inside @Component. This gives the Angular UI component access to the BannerService class created in the past section, as well as the HTTP_PROVIDERS class used to make things like AJAX calls -- note that even though the component doesn't make an AJAX call directly, the component makes use of the service's getMessageViaAjax() method which does make the AJAX call and due to the JavaScript observable used for this purpose, the component also requires access to HTTP_PROVIDERS.

Next, comes the component's constructor(private _bannerService: BannerService) { } statement. This should be familiar from the past section that described Angular dependency injection. In this case, the statement injects an instance of BannerService -- made accessible due to the providers: variable -- and makes it available through the _bannerService reference to the rest of the component class.

Once the component class has access to the service instance, it's possible to call methods that belong to the service with the reference this._bannerService. It's worth mentioning the syntax used in the component's getMessage() method uses JavaScript promise syntax -- because the service method it calls also uses a JavaScript promise -- where as the component's handleAjaxButtonClick() method uses JavaScript observable syntax -- because the service method it calls also uses a JavaScript observable.

Finally, the other important change in listing 8 is how the message field gets its initial value. Because the message field value is now provided by the Angular service, it's declared empty as message: string; in the class. But notice how and when the service is called to populate the message field.

The UI component class in listing 8 now uses the implements OnInit syntax in order to provide custom initialization logic via the ngOnInit() method. If you look for the ngOnInit() method in listing 8, you can see it calls the component's getMessage() method which is the method that makes the actual call to the Angular service and assigns the initial value to the message field. So why not simply call the getMessage() method in the component's constructor and avoid all this OnInit stuff ? constructor is a TypeScript method for class field initialization and ngOnInit is an Angular UI component life-cycle method that runs after a component's data-bound properties have been initialized. Because you're attempting to set a component's field value, the service call should be made after a component has been created, which is when ngOnInit is triggered. The component's constructor method should only be used for class field initialization (i.e. non-data related) which is why a component's dependency injection process is done in this method.