Show Menu

Basic features of Angular2

This is a draft cheat sheet. It is a work in progress and is not finished yet.

Component creation

import {Component, Input, EventEmitter} from ‘angular2/core’
     selector: ‘favorite’,
     template: `<div (click)="onClick()">
                 {{ favorite ? "I like it" : "I don't like it" }}
export class Component {
  @Input() isFavorite = false;
  @Output() change = new EventEmitter();
  onClick() {
    this.isFavorite = !this.isFavorite();
    this.change.emit( { newValue : this.isFavorite } );
Properties marked with @Inp­ut() and @Out­put() form the public API of our component. Users of our component can pass data to the component by setting the input properties and listening to its events. To fire an event, we use the emit() method of our Even­tEm­itt­er, which can take an event object as parameter.

Component usage

import {FavoriteComponent} from ‘./favorite.component’

  selector: "componentUser"
  template: ‘<favorite [isFavorite]="true" (change)="onFavoriteChange($event)"></favorite >’,
  directives: [FavoriteComponent]
export class ComponentUser {
  onFavoriteChange($event) {
    console.log("Favorite component fired change event: " + $event);
To use a component, we need to import it, add it to our directives in order to let Angular know that it needs to render the component (other­wise, the tag is just output), and use it in our template.

We can pass data to the component by setting its input properties and handle any event that are declared as outputs. For each event, we also have access to the event object via the variable $eve­nt.

Service creation

import {Injectable} from 'angular2/core';
import {Http, Response} from 'angular2/http';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/map';

import {IUser} from './iuser';

export class UserService {

  private url = '';
  constructor(private http:Http) {}

  getUsers(): Observable<IUser[]> {
    return this.http.get(this.url)
       .map(response => response.json());
Services are just regular typescript classes. @Inj­ect­abl­e() is only required if the service itself depends on other services via dependency injection. However, it is a best practice to decorate all services with @Inj­ect­abl­e().

Service usage

import {Component, OnInit} from 'angular2/core';
import MyService from "./my-service.service";

  providers: [UserService]
export class CourseComponent {

  users: Array<IUser> = undefined;

  constructor(userService: UserService) { }

  ngOnInit() {
    this.userService.getUsers().subscribe(users => { this.users = users; } });
To use a service, we need to import it, reference it in our providers and pass a reference in a constr­uctor, which lets Angular inject the service into our class.

Directive creation

import {Directive} from ‘angular2/core’;
import {ElementRef, Renderer} from ‘angular2/core’;

  selector: [myDirective],
  host: {
    ‘(onmouseenter)’ : ‘gettingFocus()’,
    ‘(onmouseleave)’ : ‘leavingFocus()’
} })
export class MyDirective {

  constructor(el: ElementRef, renderer: Renderer) { }

  gettingFocus() {
  leavingFocus() { ... }
The host section captures DOM events and maps them to methods in our directive class.
To access and modify the DOM element, we inject the element reference (which can be used to get the native DOM element) and the renderer.


{{ expression }}
<h1>{{ title }}<­/h1>
Elvis operator
{{ object­?.n­ull­abl­ePr­operty }}
{{ book?.a­pp­end­ix?.pages }}
Property binding
<img [src]=­“im­ageUrl” />
Class binding
<li [­tiv­e]=­“is­Active” />
ngClass binding
[ngCla­ss]­={'­cl­ass­Nam­e'­:ex­pre­ssion, ...}
li [ngClass]={
} />
Style binding
<button [­ckg­rou­ndC­olo­r]=­“is­Active ? ‘blue’ : ‘gray’­”>
[ngSty­le]­={­sty­leN­ame­:e­xpr­ession, ...}
<button [ngStyle]={
backgroundColor:isActive ? blue : gray,
color: canSave? 'white' : 'back'
Event binding
<button (click­)=“­onC­lic­k($­eve­nt)­”>
Two-way binding
<input type=“­text” [(ngMo­del­)]=­“fi­rst­Nam­e”>


Show/hide element
<div [hidde­n]=­“co­urs­es.l­ength == 0”>­</d­iv>
Add/remove element
<div *ngIf=­“co­urs­es.l­ength > 0”>­</d­iv>
Add/remove multiple cases
<div [ngSwitch]=“viewMode”>
<te­mplate [ngSwi­tch­Whe­n]=­“‘map’” ngSwitchDefault>
<te­mplate [ngSwitchWhen]=“‘list’”>
Creating element several times
<li *ngFor­="let course of courses, #i=index">
{{ (i+1) }} - {{ course }}

Built-in pipes

{{ course.title | uppercase }} -> ANGULAR COURSE
{{ course.title | lowercase }} -> angular course
{{­udents | number }} -> 1,234
{{ course.rating | number­:’2.2-2’ }} -> 04.97
{{ course.price | curren­cy:­’US­D’:true }} -> $99.95
{{­lea­seDate | date:’MMM yyyy’ }} -> Mar 2016
{{ course | json }} -> { name : "­Ang­ula­r", author: "­Mos­h" }
TODO: add pipe parameters

Pipe creation

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

@Pipe({ name: 'shorten' })
export class ShortenPipe implements PipeTransform {
  transform(value: string, args: string[]) {
    var limit = (args && args[0]) ? args[0] : 20;
    if (value)
      return value.substring(0, limit) + "...";
Pipes are typescript classes that implement the Pipe­Tra­nsf­orm interface and have an @Pip­e() decorator. Each pipe has a name provided through the decorator. We can access arguments to the pipe via the args parameter in the tran­sfo­rm() method.

Pipe usage

import {Component} from 'angular2/core';
import {ShortenPipe} from './shorten.pipe';

  selector: 'my-app',
  template: '{{ longText | shorten:10 }},
  pipes: [ShortenPipe]
export class AppComponent {
  longText = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua."
To use a pipe, we need to import it, reference it in our pipes and then can apply it to any fields.


vid 51

Form Contro­l/C­ont­rol­Group Properties

Value of the input field
Whether the field has been activated once
Whether the field value has been changed
Whether the field value passes validation
Validation errors for the field. May be null.

Templa­te-­driven Form (implicit controls)

<form #f="ngForm" (ngSubmit)="onSubmit(f.form)">
  <div class="form-group">
    <label for="name">Name</label>

    <!-- Input field -->
    <input ngControl="name" #name="ngForm"
      name="name" type="text"
      required minlength="3"

    <!-- Error messages -->
    <div *ngIf="name.touched && name.errors">
      <div class="alert alert-danger" *ngIf="name.errors.required">
        Name is required.
      <div class="alert alert-danger" *ngIf="name.errors.minlength">
        Name should be minimum {{ name.errors.minlength.requiredLength}} characters.
  <!-- More input elements -->

  <button class="btn btn-primary" type="submit" [disabled]="!f.valid">
We need to create a Contro­lGroup for the form and a Control for each input field. This is done by assigning the attribute ngCo­ntr­ol=­"­na­meO­fCo­ntr­ol­". We can assign a local variable to the Control using #na­meO­fCo­ntr­ol­="ng­For­m".
Implicitly generated Control objects only offer three validation rules: requ­ired, minl­eng­th, and maxl­eng­th.
Each input with an ngControl directive automa­tically gets CSS classes assigned, e.g., ng-t­ouc­hed, ng-d­irty, ng-i­nva­lid.

Model-­driven Form (explicit controls)

<form [ngFormModel]="form" (ngSubmit)="onSubmit(f.form)">
  <div class="form-group">
    <label for="name">Name</label>

    <!-- Input field -->
    <input ngControl="name" #name="ngForm"
      name="name" type="text"

    <!-- Error messages -->
    <div class="alert alert-danger" *ngIf="!name.valid">
      Name is required.
  <!-- More input elements -->

  <button class="btn btn-primary" type="submit" [disabled]="!f.valid">

The typescript file:

import {Component} from 'angular2/core';
import {ControlGroup, Control, Validators} from 'angular2/common';

  selector: 'my-form',
  templateUrl: 'my-form.component.html'
export class MyFormComponent {

  form = new ControlGroup({
     name : new Control('initial value', Validators.required)
    // one control for each input
Model-­driven forms are similar to templa­te-­driven ones, but we need to create a Cont­rol­Group with a Cont­rol for each input explicitly in the typescript class. Also, the form is bound through the directive [ngF­orm­Mod­el].

Creating custom validators

import {Control} from 'angular2/common';

export class MyValidators {
  // synchronous validator
  static cannotContainSpace(control: Control) {
    if (control.value.indexOf(' ') < 0)
      return null; // valid
    return { cannotContainSpace: true }; // invalid

  // asynchronous validator
  static shouldBeUnique(control: Control) {
    return new Promise((resolve, reject) => {
      // simulating server call
      setTimeout(function() {
        if (control.value == "duplicate")
          resolve({ shouldBeUnique: true}); // validation fails
          resolve null; // validation passes

Validators are static methods that return null in case of a passing validation and an object with the name of the validation rule as key and any additional inform­ation as value. Asynch­ronous validators return a promise instead of the object directly. In case validation depends on several inputs, we can pass the Cont­rol­Group instead of Cont­rol and add the validator to the form.

Performing validation on submit

signUp() {
  var result = authService.login(this.form.value); // call some authentication service
  if (result.error) {
     invalidLogin: true

Dirty checking

import {CanDeactivate, ComponentInstruction} from 'angular2/router';
export class MyComponent implements CanDeactivate {

  form : ControlGroup;

  routerCanDeactivate(next: ComponentInstruction, prev: ComponentInstruction) : boolean {
    if (!this.form.dirty)
      return true;
    return confirm('You have unsaved changes. Are you sure to leave?');


Reactive Extensions / Observ­ables

Common imports
import {Obser­vable} from 'rxjs/Rx';
import 'rxjs/­add­/op­era­tor­/map';
Creating observable from control group
Creating observable from control
Creating empty observable
Creating observable from object
Creating observable from array
Creating observable from range
Creating timer using observable
Creating delay using observable
Fork/J­oining observ­ables
let observ­able1 : Observ­abl­e<a­ny> = Observ­abl­e.of({ user: 'user', pass: 'pass'}).delay(1000);
let observ­able2 : Observ­abl­e<a­ny> = Observ­abl­e.of({ unread­Mes­sages: 100}).delay(2000);
let combined : Observ­abl­e<a­ny> = Observ­abl­e.f­ork­Joi­n(o­bse­rva­ble1, observable2);
// returns [{user: "­use­r", pass: "­pas­s"}, {unrea­dMe­ssages: 100}]
Error handling
x => consol­e.l­og(x),
e => console.error(e)
Retry in case of error
Catching errors
let failed­Obs­ervable : Observ­abl­e<a­ny> = Observ­abl­e.t­hro­w(new Error(­"­Cannot reach server"));
.catch­((err) => Observ­abl­e.o­f("d­efault data"))
.subsc­ribe(x => consol­e.l­og(x))
Setting timeout
Notifi­cation on completion
// pass callback as third argument when subscribing
x => consol­e.l­og(x),
e => consol­e.e­rro­r(e),
() => console.log("finished")
Angular only ships with a minimum of Rx features for perfor­mance reasons. To use more functions (e.g. "­map­"), we have to import it additi­onally to the Observable (import 'rxjs/­add­/op­era­tor­/ma­p';).


Setting up the base URL
// in index.h­tml, directly after <he­ad> tag
<base href="/­">
Implem­enting main router
import {Route­Config, ROUTER­_DI­REC­TIVES, ROUTER­_PR­OVI­DERS} from '@angular/router';
direct­ives: [ROUTE­R_D­IRE­CTIVES, ...]
{ path: '/home', component: HomeCo­mponent },
{ path: '/user­/:u­serId', component: UserCo­mponent },

constr­uct­or(­private router: Router) {}

ngOnInit() { // default route
Catch-all route
{ path: '*', redire­ctTo: ['/home'] }
Use route
Create router links
import {ROUTE­R_D­IRE­CTIVES} from '@angular/router';
<a [route­rLi­nk]­="['­/home', params­]">Go Home</a>
<a [route­rLi­nk]­="['­/user', { "­use­rId­": userId } ]">Go to user page</­a>
Manually trigger route
import {Router} from '@angular/router';
this.router.navigate(['/user', {userId : }]);
Using parame­terized router
<a [route­rLi­nk]­="['­/user', {userId:}]">

constructor(..., routeP­arams: RouteP­arams) {

Help Us Go Positive!

We offset our carbon usage with Ecologi. Click the link below to help us!

We offset our carbon footprint via Ecologi