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