Barbarian Meets Coding
barbarianmeetscoding

WebDev, UX & a Pinch of Fantasy

15 minutes readangular

Angular 2 Wiki

Angular 2 is the new improved version of the ever popular JavaScript framework AngularJS. Angular 2 is a re-imagining of Angular applying all lessons learned from v1.x and promotes a component based architecture while leveraging new features of ES2015 (or TypeScript) like classes and modules.

Setting up Your Development Environment

In order to set up your development environment check this angular2 tutorial that will guide you through the process.

If you are an experienced developer you might want to jump straight to using an angular2 generator from the yeoman project.

From Angular 1 to Angular 2

  • New and more explicit way to bootstrap an app in Angular 2. Now we use a bootstraper from angular2/platform/browser (platform specific) and point it to the root component of the application (f.i. bootstrap(MainComponent)) instead of Angular 1 ng-app.
  • Components in Angular 2 are like a directive with a template, an isolated scope and a controller.
  • ng-repeat becomes *ngFor, ng-if becomes *ngIf.
  • data binding
    • interpolation just like in Angular 1 but removing vm (from {{vm.person.age}} to {{person.age}}).
    • one-way data binding in Angular 1 ng-bind in Angular 2 is called property binding and denoted inside [] (f.i. <person-detail [id]="person.id" />).
    • event binding from Angular 1 ng-click, ng-change, etc to Angular 2 (click), (change).
    • two-way data binding from Angular 1 ng-model to Angular 2 [(ngModel)].
  • Angular 2 has a lot less directives than Angular 1. In Angular 2 you can leverage the property-binding syntax to bind to DOM properties and events directly. (40+ angular directives according to John papa)
  • Angular 2 consolidates the idea of service classes. From Angular 1 service, factory, providers, constants and values we get Angular 2 services which are just classes.
  • You need to be more explicit with dependency injection and signal within a component configuration which services and which other components you are going to use.
  • Angular 1 modules become ES6 modules in Angular 2
  • Angular 1 filters become Angular 2 pipes
  • Angular 2 http uses mainly rxjs instead of promises (although you can converted a stream into a promise)
  • Angular 2 routing
    • use @RouteConfig decorator instead of ng1 $routeProvider
    • use <router-outlet instead of <ng-view>
    • use [router-link]="link" instead of ng-href
    • use RouteParams instead of $routerParams
    • use Router instead of $router
    • child routes built-in ng2 (sub-components can define their own routing)

An Overview Of Angular 2

Angular 2 conceptual model is an improvement over Angular 1 in two main ways:

  1. it improves many of its existing parts (f.i. like modules which are now standard ES6 modules)
  2. it condenses the number of concepts within the framework into a more cohesive unit with less redundant components (*f.i. like unifying services and factories, and providing a much better way to create components/directives)

These are the core building blocks of Angular 2:

  • Modules which group or encapsulate functionality within the application
  • Components which represent a unified View + View Model + Styles unit that you can compose to create an application
  • Templates which represent a view with a special syntax to enhance html with Angular2 functionality like data binding
  • Metadata that wires everything together, a view with a view model with styles, etc
  • Data Binding to flow data changes between view and view model and vice versa
  • Services to encapsulate and reuse non-view related logic that can be used by different parts of an application
  • Directives
  • Dependency Injection to inject the necessary dependencies for a given component/service at runtime and provide flexibility, extensibility and testability to the framework and your application

Modules

Angular 2 is a modular framework where every piece of functionality is encapsulated within a module and exposed to other parts of the application as a service (in the general sense). There’s usually two kinds of modules, those that encapsulate a piece of functionality with a single reponsibility (like a single component or a service) and those that group other modules to expose them through a unified manner (for instance the angular/core module that acts as a facade over many other modules in Angular 2).

Angular 2 also promotes the use of modules in your own application code. For instance, to create a component you would import the Component decorator from angular/core like this:

import { Component } from 'angular/core'

@Component({
  selector: 'hello-world',
  templateUrl: './hello-world.component.html',
  styleUrls: ['./hello-world.component.css'],
})
export class HelloWorldComponent {}

And you would export your own HelloWorld component as a service to the rest of the application. This results in an application as a set of modules where some of them provide something of value and others consume it.

Note that using ES6 modules is not a required in Angular 2, it is the recommended approach since it provides a much better developer experience than the alternative.

Components

Components are similar to View Models in the MVVM pattern (or controllers in Angular 1) they control a piece of UI by providing it with data and logic.

export class HelloWorldComponent implements OnInit{
    public helloWorld:string = "Hello World";
    public persons:Person[];
    public selectedPerson:Person;

    constructor(private _personsService: PersonService){}
    ngOnInit(){
        this.persons = _personsService.getPersons();
    }
    sayHi(person){
        this.selectedPerson = person;
    }
}

Together with a Template, Metadata and optionally styles, they constitute an isolated and encapsulated unit of UI. The view (or template) represents how the component will look like when rendered on the browser, the view model contains all the necessary logic to provide the view with rich functionality and data, the styles provide the component with a specific look and feel, and the metadata wires everything together. Noteworthy is the fact that component styles are only applied to the component itself, that is, they are scoped to the component.

Communicate Components

  • @Input decorated properties allow a parent controller to communicate and pass data into a child controller
  • @Output decorated events allow a child controller to communicate and pass data into a parent controller
@Component({....})
export class PersonComponent {
    @Input() person: Person;
    @Output() changed = new EventEmitted<Person>();

    // codes
}

This lets you pass a person to the PersonComponent from a parent component:

<person-detail [person]="selectedPerson"></person-detail>

And subscribe to the changed event:

<person-detail [person]="selectedPerson" (changed)="updateBilling()"></person-detail>

Communicating From a Parent to a Child Component

There will be ocassions where you want a parent component to communicate with a child component. A way to achieve this is trough the @ViewChild decorator:

export class PersonListComponent {
  // codes codes...
  @ViewChild(SearchComponent) search: SearchComponent

  updatePersons() {
    // update...
    search.clear()
  }
}

Using the @ViewChild decorator in this example let’s us call the clear method defined within the SearchComponent that is a child of the PersonListComponent.

Templates

Templates represent the view part of a component, they augment HTML with new syntax and behavior to enable things such as interpolation, two-way data binding, etc.

This here is an example of an Angular 2 template:

<h2>{{ helloWorld }}</h2>
<p>Say hi to Everyone!</p>
<div *ngFor="#person of persons" (click)="sayHi(person)">
  {{hero.name}}
</div>
<person-salute *ngIf="selectedPerson" [person]="selectedPerson"></person-salute>

That contains a lot of special stuff in addition to vanilla HTML:

  • {{ helloWorld}} that is bound to the helloWorld variable and displays its value (just like in Angular1)
  • *ngFor="#person of persons" that works like ng-repeat and is going to replicate the subtemplate decorated with this attribute and declare a local variable person that you can use inside this subtemplates
  • (click) that lets you set up a click event handler
  • a person-salute component that encapsulates a person salute
  • an *ngIf="selectedPerson" that works like ng-if and is going to decide whether to add this element to the DOM based on an expression
  • a [person]="selectedPerson" that passes the selectedPerson to the person-salute component

Metadata

Metadata wires up the different parts that we’ve seen thus far. For instance, the HelloWorldComponent is just a class, it doesn’t become an Angular 2 Component until we decorate it with the Component decorator:

import {Component} from 'angular/core';

@Component({
  selector: 'hello-world',
  templateUrl: 'app/hello-world.component.html',
  directives: [PersonSalute],
  providers:  [PersonsService]
})
export class HelloWorld { ... }

The Component decorator associates a bunch of metadata to the HelloWorld class that tells Angular 2 how to work with it and render it in your application at runtime. Some of these are:

  • selector: which tells angular which custom html he must associate this component to
  • templateUrl: a url for the template to use when rendering this component
    • template also lets you define the template directly
  • an array of directives to tell angular which components or directives will be used in this particular component
  • an array of styleUrls that lets you define custom specific styles for the component
  • an array of providers that tells Angular2 how to inject dependencies (like services) inside a component

There are other decorators like @Injectable that tells angular that a particular something (like a service) can be injected or @RouterConfig that lets you configure routing in your application.

Data Binding

Data binding lets you bind data and interaction between a template and a component in a declarative manner. Angular offers four types of data binding (which can be to the DOM, from the DOm and two-way):

  • interpolation lets you display a component’s property in a view. It looks like this: {{helloWorld}}
  • the property binding lets you pass data between parent and child components. For instance [person]=selectedPerson sends the selectedPerson property in the parent to the person property in the child component.
  • the event binding lets you bind DOM events to methods within your component. It looks like this (click)=destroyUniverse()
  • two-way data binding combines property and event binding into a single notation with [(ngModel)] and establishes a two-way data binding between template and component.

One Way Binding - From Component to View

You have these three ways of doing one-way data binding directed from the component to the view/template:

  • Interpolation: {{person.name}}
  • Property Binding: [targetProperty]="expression"
    • Some examples: [person]="selectedPerson" or [style.backgroundColor]="#FFF"
    • More examples: src="{{person.imageUrl}} or [src]="person.imageUrl"
    • More examples: [ngClass]={'active': isAlive} or [class.active]="isAlive"
    • For attributes use attr, for example: <image [attr.aria-label]="button" ...>
      • What are attributes and why are they different from properties?
        • Attributes are any valid HTML attributes
        • Properties are properties of a DOM element
    • Alternative syntax bind-targetProperty="expression"
      • For instance: bind-src="person.imageUrl"

One Way Binding - From View to Component

There’s one way to do one-way data binding from a view/template to a component: event bindings.

  • Event Binding: (event)="expression"
    • Example: <button (click)="sendMail()">Send mail</button>
    • Example custom events: <pomodoro-timer (pomodoroCompleted)="completeTask()"></pomodoro-timer>
      • this means that whenever the pomodoro-timer emits a pomodoroCompleted event we are going to execute the completeTask method and handle that event in our component
    • Access event information with $event: <input [value]="person.name" (input)="vehicle.name=$event.target.value"> (convoluted way to do two-way binding XD)
    • Alternative syntax on-event="expression"

You can define custom events in your components like this:

@Output() onPomodoroCompleted: new EventEmitter();
pomodoroCompleted() { this.onPomodoroCompleted.emit(); }

Two Way Binding

The two way data binding let’s you keep your view and underlying component in sync by updating the view whenever the component changes and vice versa.

  • Two-way data binding: [(ngModel)]="expression"
    • Example: [(ngModel)]="person.name"
    • Alternative syntax bindon-ngModel="expression"

Directives

Angular 2 directives let you tell Angular how to render or operate on a particular piece of DOM. They are classes that are decorated with the @Directive decorator. There are different types of directives:

  • components are a special type of directive that is associated to a template. The @Component decorated is a special version of @Decorator
  • structural directives like *ngFor and *ngIf let you alter the DOM by adding or removing nodes
  • attribute directives add behavior or alter the appearance of a particular element. For instance, the ngModel directive that implements two-way data binding is an *attribute directive. It augments the behavior of a normal input element by setting its value attribute when there are changes in the underlying property and by handling the change event to signal user caused changes to the component.

Built-in Directive

  • ngClass helps you set class of a given element (like ng-class in angular 1)
    • but you can also use [class.className]
    • ngClass raison d’etre is that it lets you set serveral classes at once
  • ngStyle helps you set styles for a given element (like ng-style in ng1)
    • but you can also use [style.property]
    • ngStyle raison d’etre is that it lets you set several styles at once
  • *ngFor is the new ng-repeat
    • new syntax is *ngFor="#person of persons" (you can use var instead of #)
    • also indexes *ngFor="#person of persons, #i=index"
  • *ngIf is the new ng-if
  • *ngSwitch is the new ng-switch

Services

Services in Angular 2 are pretty similar to services in Angular 1, they are a way to encapsulate a piece of logic and make it available to other parts of an application. They are represented by a class:

export class Logger {
  log(msg: any)   { console.log(msg); }
  error(msg: any) { console.error(msg); }
  warn(msg: any)  { console.warn(msg); }
}

export class PersonsService{
  constructor(
    private logger: Logger) { }

  private persons:Person[] = getPersons();

  getAll() {
    return Promise.resolve(persons);
    this.logger.log(`Fetched ${persons.length} persons.`);
  }
  get(id){
    var person = persons.find(p => p.id);
    if (person) {
      this.logger.log(`Fetched ${person}.`);
      return Promise.resolve(person);
    } else {
      var errorMessage = `couldn't find person with id=${id}`;
      this.logger.error(errorMessage);
      return Promise.reject(errorMessage);
    }
  }
}

Ideally, components will be a very thin layer that ties models to views (templates) and delegates all complicated logic to services that perform a single task. This kind of approach results in a well architected application that is flexible, extensible, testable and easy to maintain and reason about. It also produces systems that have a lot of small classes that do one thing. Managing a lot of small classes and dependencies by hand is time consuming and that’s why we use dependency injection to handle all dependencies for us.

Dependency Injection

// HERE continue reading from docs…

Getting Started

// HERE More detail view of each item in Angular…

Additional Notes

Structural Directives

Structural directives like *ngFor and *ngIf alter the structure (DOM) of your application. The asterisk is prepended to highlight the fact that a specific directive is going to alter the structure of your view.

Pipes

Pipes let you encapsulate data transformations into nice utility functions that you can then reuse and apply on your template bindings. Angular 2 pipes correspond to angular 1 filters.

Built-in Pipes

  • uppercase example {{person.name | uppercase}}
  • lowercase example {{person.name | lowercase}}
  • json: print output in json format (f.i. {{person | json}})
  • date: format dates: {{person.dateOfBirth | date:'ddMMYY'}}
  • currency example {{person.estimatedWealth | currency}}
  • percent example {{person.comparativeDebt | percent:'1:1-1'}} where 1:1-1 means minIntegerDigits:minFractionDigits-maxFractionDigits
  • number (as above)

Async Pipe

The async pipe lets you subscribe to a Promise or an observable and returns the last value emitted.

Custom Pipes

You can create very own custom pipes by using the @Pipe decorator and implementing the PipeTransform interface:

import { Pipe, PipeTransform } from 'angular2/core'

@Pipe({ name: 'toMWhs' })
export class ToMWhs implements PipeTransform {
  transform(value: string, args: any[]) {
    return parseFloat(value) / 1000
  }
}

Using Pipes

In order to use pipes within your component you need to declare them within the @Component decorator pipes property:

import { ToMWhs } from '../pipes/toMWhs.pipe';

@Component({
  // etc
  pipes: [ToMWhs]
});

What to Learn More? Check this references!


Jaime González García

Written by Jaime González García , dad, husband, software engineer, ux designer, amateur pixel artist, tinkerer and master of the arcane arts. You can also find him on Twitter jabbering about random stuff.Jaime González García