Angular Workshop

 

Andrei Antal

https://slides.com/andreiantal/angular_workshop/

ABOUT ANGULAR 2

But first a bit of history

2009 - Angular project @Google (Misko Hevery, Adam Abrons)​

2012 - Angular 1.0 release

  • 2-way data binding
  • Custom elements (directives)
  • Dependency Injection

2013 - React from Facebook

  • Virtual DOM
  • JSX (HTML + JavaScript)
  • Unidirectional data flow

2014 - Angular 2 - first announcement

2015 - Angular 1.4

2016 - Angular 1.5

2016  - Angular 2 - final release - 14 september

2017 - Angular 4 - march

But first a bit of history

2017 - Angular 5 - soon :) (in RC now)

About Angular 1

What's new in Angular 2

What's new in Angular 2

Features:

  • Simplified
  • Blazing fast
  • New compiler
  • New change detection mechanism
    • introducing zones
    • models as observables
  • New module system - ngModule
    • using es6 modules
    • easier to implement lazy loading
  • dropped bower in favor of npm for package management

What's new in Angular 2

Features:

  • New DI mechanism
  • Component based architecture (already from Angular 1.5)
  • Improved support for server side rendering - AOT compilation
  • Supporting modern web standards (shadow DOM)

All platforms

All platforms

Community

ES6 AND TYPESCRIPT

JavaScript - ES5

Common problems with Javascript today

  • Dynamic typing
  • Lack of modularity
  • Verbose patterns to achieve some code sanity

ES6/ES2015

  • Classes
  • Arrow Functions
  • Template Strings Inheritance
  • Constants and Block Scoped Variables ...spread and ...rest
  • Destructuring
  • Modules

Classes

class Pizza {
    constructor(toppings) {
        this.toppings = toppings
    }

    listToppings() {
        toppings.forEach(function(topping) {
            console.log(topping.toString();
        }
    }
}

var pizza = new Pizza();
pizza.listToppings();

Arrow functions

// ES5 function

const sum = function(num1, num2) {
    return num1 + num2;
};

// ES6 arrow function

const sum = (num1, num2) => { return num1 + num2 };
// ES5 function

const getTempItem = function(id) {
    return {
        id: id,
        name: "Temp"
    };
};

// ES6 arrow function

const getTempItem = id => ({ id: id, name: "Temp" });
  • does not bind its own this, arguments, super or new.target

Template strings

var firstName = "Andrei",
    lastName = "Antal";

// ES5

var fullName = "The full name is: " + firstName + " " + lastName


// ES6 template strings

var fullName = `The full name is: ${firstName} ${lastName}`;

Const and let

// ES5

function() {
  if(true) {
    var x = 1;
  }
  console.log(x) // 1
}

// ES6

function() {
  if(true) {
    let x = 1;
  }
  console.log(x) // ReferenceError: x doesn't exist here
}
function() {
  const a; // error, need to initialize const
  const b = 1;
  b = 2; // error cannot reasign
}

Destructuring

const animal = {
  name: 'Dog',
  sound: 'wof'
};

function makeSound(options) {
  options.name = options.name || 'animal';
  console.log(`The ${options.animal} goes ${options.sound}`)
}
function makeSound({name = 'animal', sound}) {
  console.log(`The ${name} goes ${sound}`)
}

makeSound(animal);
let options = {
  repeat: true,
  save: false
};

let {repeat, save} = options;

console.log(repeat); // true
console.log(save); // false

Others​

  • Rest and spread
  • Modules
  • Enhanced Objects
  • Iterators
  • Generators
  • Modules
  • Proxies

TypeScript

Static typing

let isDone: boolean = false;
let height: number = 6;
let name: string = "bob";
let list: number[] = [1, 2, 3];
let list: Array<number> = [1, 2, 3];
enum Color {Red, Green, Blue};
let c: Color = Color.Green;
let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false; // okay, definitely a boolean

Classes ++

class Person {
    name: string;
    nickName?: string;
    
    constructor(name: string) {
        ...
    }
}

const p = new Person("Andrei");

Interfaces

interface ClockInterface {
    currentTime: Date;
    setTime(d: Date);
}

class Clock implements ClockInterface {
    currentTime: Date;
    setTime(d: Date) {
        this.currentTime = d;
    }
    constructor(h: number, m: number) { }
}

Generics

//declare
private _possessions: Array<Thing>;

constructor(){
    //assign
    this._possessions = new Array<Thing>();
}

Decorators

@Component({
    selector: 'my-app',
    styles: ['h1 {color:#545454;}'] 
    template: `
    <h1>
        Hello from the {{componentName}}.
    </h1>
    `
})
export class AppComponent {
    @Input() componentName = 'AppComponent';
}

.

  • Functions that are invoked with a prefixed @ symbol, and immediately followed by a class, parameter, method or property.

BOOTSRAP

Bootstrap

  • No more ng-app directive for boostrap\

 

  • Bootstarp is done explicitly

 

  • There is one Root Module which has one Root Component

 

  • Everything else is a child of the two

Bootstrap


import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import {AppModule} from './app';


platformBrowserDynamic().bootstrapModule(AppModule)

import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent }  from './app.component';

@NgModule({
  imports:      [ BrowserModule ],
  declarations: [ AppComponent ],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }
  • JIT (Just In Time) compilation

AppModule


import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent }  from './app.component';

@NgModule({
  imports:      [ BrowserModule ],
  declarations: [ AppComponent ],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }

index.html

....

<body>
    
    <my-app><!-- content managed by Angular --></my-app>

....

</body>

....

AOT compilation

// The browser platform without a compiler
import { platformBrowser } from '@angular/platform-browser';

// The app module factory produced by the static offline compiler
import { AppModuleNgFactory } from './app/app.module.ngfactory';

// Launch with the app module factory.
platformBrowser().bootstrapModuleFactory(AppModuleNgFactory);

NGMODULES

NgModules

  • Organize the app logic and code and include external libraries
  • Every angular app has at least 1 module - the root module
  • The other modules are usually organized in feature modules
import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent }  from './app.component';

@NgModule({
  imports:      [ BrowserModule ],
  declarations: [ AppComponent ],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }

NgModules

 

Main uses

  • Declare which components, directives, and pipes that belong to the module.
  • Make some of those classes public so that other component templates can use them.
  • Import other modules with the components, directives, and pipes needed by the components in this module.
  • Provide services at the application level that any application component can use.

NgModules

Providing services

  • services declared in the providers array are available for all the components of that module
  • one injector per application, services in each module can be used in all the application


Importing other modules

  • Make use of elements in other modules
  • Modules do not inherit from parent module 

NgModules

Providing services

  • services declared in the providers array are available for all the components of that module
  • one injector per application, services in each module can be used in all the application


Importing other modules

  • Make use of elements in other modules
  • Modules do not inherit from parent module 

NgModules

Lazy load modules

  • Using the router module, specify which modules to lazy load on a route change

 

import { NgModule }             from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

export const routes: Routes = [
  { path: '', redirectTo: 'contact', pathMatch: 'full'},
  { path: 'details', loadChildren: 'app/details/details.module#DetailsModule' },
  { path: 'users', loadChildren: 'app/user/user.module#UserModule' }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule {}

DEPENDENCY INJECTION

Dependency Injection

Features

 

  • Framework for resolving dependencies
  • Automatic creation and resolution
  • The injector - created at bootstrap; configure it byadding providers
  • Register providers
    • in modules - each service is registered in the root injector => each service registered in the module is available in the entire application
    • in components

Dependencies

import { FormsModule } from '@angular/forms';
import { HttpModule }  from '@angular/http';
import { UsersService } from './users.service';

@NgModule({
  imports: [ BrowserModule, FormsModule, HttpModule ],
  declarations: [ App ],
  providers: [ UsersService ],
  bootstrap: [ App ]
})
export class AppModule {}

Services - Injectables

import { Injectable } from '@angular/core';

@Injectable()

export class ExampleService {
    someMethod() {
        return 'Hey!';
    }
}
import { Component } from '@angular/core';
import { ExampleService } from './example.service';


@Component({
    selector: 'my-app',
    template: '<h1>{{ title }}</h1>',
    providers: [ExampleService]
})

export class AppComponent { 
    title: string;

    constructor(private _exampleService: ExampleService) { }

    ngOnInit() { this.title = this._exampleService.someMethod(); }
}

Injector providers

 

  • class ->[{ provide: Logger, useClass: Logger }]
    • token for locating and registering the provider
    • creation object - can be the same, or alternative classes

 

  • alias class -> [NewLogger, { provide: OldLogger, useExisting: NewLogger}]
    • useClass - would create 2 instances of NewLogger

  • value provider -> [{ provide: Logger, useValue: silentLogger }]

COMPONENTS

Component architecture

Component architecture

Component

  • @Component annotation
  • Communication
    • Inputs, @Inputs
    • Outputs, @Outputs
  • Component lifecycle hooks
  • Host element interactions

Component

import { Component } from '@angular/core';
import { SomeService } from './someService';

@Component({
  selector: 'my-component',
  template: `
    <div>
        Hello component
    </div>
  `,
  styles: [`div { color: red }`],
})
export class MyComponent {
  @Input() name;
  @Output() onClick: EventEmitter;
  
  constructor(private someService: SomeService) {
  }

  ...
}

Lifecycle Hooks

import {Component, OnChanges, OnInit, OnDestroy} from 'angular2/core';

@Component()
export class myComponent implements OnChanges, OnInit, OnDestroy { 
  /* 1 */ constructor() { }

  // called when an input or output binding changes
  /* 2 */ ngOnChanges(changes) { }   
  
  // after child initialisation
  /* 3 */ ngOnInit() { } 
  
  // just before is destroyed
  /* 4 */ ngOnDestroy() { } 
}

Data flow

Component types

TEMPLATING

Templates

import { Component } from '@angular/core';
import { SomeService } from './someService';

@Component({
  selector: 'my-component',
  template: `
    <div>
        Hello component
    </div>
  `,
  styles: [`div { color: red }`],
})
export class MyComponent {
  @Input() name;
  @Output() onClick: EventEmitter;
  
  constructor(private someService: SomeService) {
  }

  ...
}

Template syntax

Syntax Binding type
<h1>{{title}}</h1> Interpolation
<button [disabled]="disabled"> Property
<li [class.active]="isActive"></li> Class
<div [style.width.px]="mySize"> Style
<button (click)="onClick($event)"> Event
<input [(ngModel)]="data.value"> Two-way

HTTP

HTTP Services

  • Singleton instance
  • Share state between Components
  • Leverage Observables

Using Data services

HTTP Module

  • Primary protocol for client/server communications
  • Implements XMLHttpRequest (XHR) and JSONP
  • Http methods:  GET, POST, PUT, DELETE, PATCH and HEAD

HTTP Module

// app.module.ts
import { HttpModule }  from '@angular/http';
@NgModule({ 
  imports: [HttpModule], ... 
})
export class AppModule {}

Creating a HTTP Service

// src/users.service.ts
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';

@Injectable()
export class UsersService {
  constructor(private http: Http) { }
  get() {
    return this.http.get('/assets/users.json')
      .map(response => response.json().users)
      .retryWhen(errors => errors.delay(2000));
  }
}

Consuming a HTTP Service

import { Component } from '@angular/core';
import { UsersService } from './users.service';

@Component({
  selector: 'users',
  template: `<h1>Users</h1>
    <tr *ngFor="let user of userslist">
      <td>{{user.username}}</td>
    </tr>`
})
export class Users {
  private userslist;
  
  constructor(users: UsersService) {
    users.get().subscribe( userResult => this.usersList = userResult );
  }
}

Consuming a HTTP Service

Async pipe

import { Component } from '@angular/core';
import { UsersService } from './users.service';

@Component({
  selector: 'users',
  template: `<h1>Users</h1>
    <tr *ngFor="let user of userslist | async">
      <td>{{user.username}}</td>
    </tr>`
})
export class Users {
  private userslist;
  
  constructor(users: UsersService) {
    this.usersList = users.get();
  }
}

RxJS

 

Streams

Observables

Observables vs promises

myObservable.subscribe(successFn, errorFn)

        myPromise.then(successFn, errorFn)
myObservable.subscribe(successFn, errorFn, completeFn)

        myPromise.then(successFn, errorFn)
  • Observables handle more than one value over time, so we need  complete function

Why observables

  • Flexible: sync or async
  • Powerful operators
  • Less code to write

ROUTER

ROUTER

Main features

  • Url based navigation
  • Nested routes
  • Navigation guards
  • Resolvers
  • Easy lazy loading, preloading

Configure routes

import { Routes, RouterModule } from '@angular/router';
import { Home } from './home.component';
import { About } from './about.component';
import { NotFound } from './notfound.component';

const appRoutes: Routes = [
  { path: '', redirectTo: 'home', pathMatch: 'full' },
  { path: 'home', component: Home },
  { path: 'about', component: About },
  { path: '**', component: NotFound }, //always last
];

export const AppRouting = RouterModule.forRoot(appRoutes, { useHash: true });

FORMS

FORMS

Template driven forms

  • Two-way data binding
    • [(ngModel)]
  • Change tracking
    • ngForm
  • Standard validations

Model driven / Reactive

  • Driven programmatically
    • FormBuilder, FormGroup, FormControll
  • Reactive APIs
    • eg - valueChanges
  • Composable Validations

Form/Control states

  • States
    • touched, untouched
    • pristine, dirty
    • valid, invalid
  • Examples
    • f.form.valid, email.valid
  • CSS classes
    • ng-valid, ng-invalid

Form example

@Component({
  template: `
    <form #f="ngForm" (submit)="onSubmit(f.form.value)">
        <input type="email" 
           [(ngModel)]="model.email"
           name="email"
           #email="ngModel"
           required>
        <div [hidden]="email.valid">Email is required</div>
        <button type="submit" [disabled]="!f.form.valid">Submit</button>
    </form>`
})
export class Contact {
  model = {};

  onSubmit(value) {
    console.log(`Submitted: ${JSON.stringify(value)}`);
  }
}

DEVELOPMENT

What do we need

Angular libraries:

  • @angular/core
  • @angular/compiler
  • @angular/platform-browser
  • @angular/platform-browser-dynamic
  • @angular/common
  • @angular/forms
  • @angular/router
  • @angular/http

What else

Polyfils and extra libraries:

  • core-js
  • zone.js
  • RxJS

Angular CLI

  • The Angular CLI makes it easy to create an application that already works, right out of the box
// installing
$ npm install -g @angular/cli

// scaffold the project
$ ng new PROJECT_NAME
$ cd PROJECT_NAME

// start the project
$ ng serve

// generate components 
$ ng g component my-new-component

https://github.com/IncrementalCommunity/Angular2_Workshop_Voxxed

THANKS!

Angular Workshop

By Andrei Antal

Angular Workshop

Angular 2 with TypeScript workshop @Voxxed Days Bucharest 2017

  • 1,293