Show Menu
Cheatography

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’
@Component({
     selector: ‘favorite’,
     template: `<div (click)="onClick()">
                 {{ favorite ? "I like it" : "I don't like it" }}
                </div>
                `
})
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’

@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';

@Injectable()
export class UserService {

  private url = 'http://jsonplaceholder.typicode.com/users';
  
  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";

@Component({
  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’;

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

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

  gettingFocus() {
    this.renderer.setElementStyle(this.el.nativeElement.style.color='red')
  }
  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.

Bindings

Interp­olation
{{ expression }}
<h1>{{ title }}<­/h1>
Elvis operator
{{ object­?.n­ull­abl­ePr­operty }}
{{ book?.a­pp­end­ix?.pages }}
Property binding
[prop­ert­y]­="ex­pre­ssi­on"
<img [src]=­“im­ageUrl” />
Class binding
[class.c­las­sNa­me­]="e­xpr­ess­ion­"
<li [class.ac­tiv­e]=­“is­Active” />
ngClass binding
[ngCla­ss]­={'­cl­ass­Nam­e'­:ex­pre­ssion, ...}
li [ngClass]={
'active':isActive,
'passive':!isActive
} />
Style binding
[style.s­tyl­eNa­me­]="e­xpr­ess­ion­"
<button [style.ba­ckg­rou­ndC­olo­r]=­“is­Active ? ‘blue’ : ‘gray’­”>
ngStyl­eBi­nding
[ngSty­le]­={­sty­leN­ame­:e­xpr­ession, ...}
<button [ngStyle]={
backgroundColor:isActive ? blue : gray,
color: canSave? 'white' : 'back'
}/>
Event binding
(even­t)­="ex­pre­ssi­on"
<button (click­)=“­onC­lic­k($­eve­nt)­”>
Two-way binding
[(ngMo­del­)]=­"­pr­ope­rty­"
<input type=“­text” [(ngMo­del­)]=­“fi­rst­Nam­e”>

Templates

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

Built-in pipes

uppercase
{{ course.title | uppercase }} -> ANGULAR COURSE
lowercase
{{ course.title | lowercase }} -> angular course
number
{{ course.st­udents | number }} -> 1,234
{{ course.rating | number­:’2.2-2’ }} -> 04.97
currency
{{ course.price | curren­cy:­’US­D’:true }} -> $99.95
date
{{ course.re­lea­seDate | date:’MMM yyyy’ }} -> Mar 2016
json
{{ 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';

@Component({
  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.

Todos

ngContent
vid 51

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

value
Value of the input field
touche­d/u­nto­uched
Whether the field has been activated once
dirty/­pri­stine
Whether the field value has been changed
valid
Whether the field value passes validation
errors
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"
      class="form-control"
      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>
      <div class="alert alert-danger" *ngIf="name.errors.minlength">
        Name should be minimum {{ name.errors.minlength.requiredLength}} characters.
      </div>
    </div>
  </div>
 
  <!-- More input elements -->

  <button class="btn btn-primary" type="submit" [disabled]="!f.valid">
    Submit
  </button>
</form>
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"
      class="form-control"
      name="name" type="text"
    />

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

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


The typescript file:

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

@Component({
  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
        else
          resolve null; // validation passes
        },1000);
    });
  }

}
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) {
    this.form.find('username').setErrors({
     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
this.f­orm.va­lue­Changes
Creating observable from control
this.f­orm.fi­nd(­"­inp­utF­iel­d").v­al­ueC­hanges
Creating empty observable
Observ­abl­e.e­mpty()
Creating observable from object
Observ­abl­e.o­f(o­bject)
Creating observable from array
Observ­abl­e.f­rom­Arr­ay(­[1,­2,3])
Creating observable from range
Observ­abl­e.r­ang­e(1,3)
Creating timer using observable
Observ­abl­e.i­nte­rva­l(1000)
Creating delay using observable
Observ­abl­e.d­ela­y(1000)
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
observable.subscribe(
x => consol­e.l­og(x),
e => console.error(e)
)
Retry in case of error
observ­abl­e.r­etry(3)
Catching errors
let failed­Obs­ervable : Observ­abl­e<a­ny> = Observ­abl­e.t­hro­w(new Error(­"­Cannot reach server"));
failedObservable
.catch­((err) => Observ­abl­e.o­f("d­efault data"))
.subsc­ribe(x => consol­e.l­og(x))
Setting timeout
observ­abl­e.t­ime­out­(200)
Notifi­cation on completion
// pass callback as third argument when subscribing
observable.subscribe(
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';).

Routing

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, ...]
...
...
@RouteConfig([
{ path: '/home', component: HomeCo­mponent },
{ path: '/user­/:u­serId', component: UserCo­mponent },
...
])

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

ngOnInit() { // default route
this.router.navigate(['/home']);
}
Catch-all route
{ path: '*', redire­ctTo: ['/home'] }
Use route
<ro­ute­r-o­utl­et>­</r­out­er-­out­let>
Create router links
import {ROUTE­R_D­IRE­CTIVES} from '@angular/router';
...
directives: [ROUTER_DIRECTIVES]
...
<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(['/home']);
this.router.navigate(['/user', {userId : user.id }]);
Using parame­terized router
<a [route­rLi­nk]­="['­/user', {userId: user.id}]">

constructor(..., routeP­arams: RouteP­arams) {
this.u­ser­Id=­rou­teP­ara­ms.g­et­("us­erI­d");

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