slides.com/gerardsans | @gerardsans
800
500
ES6 (ES2015)
TypeScript
/home
/users
/about
/users/34
<!DOCTYPE html>
<html>
<head>
<!-- Polyfill(s) for older browsers -->
<script src="https://unpkg.com/core-js/client/shim.min.js"></script>
<script src="https://unpkg.com/zone.js@0.6.17?main=browser"></script>
<script src="https://unpkg.com/reflect-metadata@0.1.3"></script>
<script src="https://unpkg.com/systemjs@0.19.27/dist/system.src.js"></script>
<script src="systemjs.config.js"></script>
<script>System.import('app');</script>
</head>
<body>
<my-app>
Loading...
</my-app>
</body>
</html>
// main.ts
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';
platformBrowserDynamic().bootstrapModule(AppModule);
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
@NgModule({
imports: [ BrowserModule, UsersModule, appRouting ],
declarations: [ AppComponent, Home, ... ],
providers: [ LoginService, AuthCanActivate ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
import { Component } from '@angular/core';
@Component({
selector: 'my-app', // <my-app>Loading...</my-app>
template: `...`
})
export class App {
constructor() { }
}
/home
/users
import { Injectable } from '@angular/core';
@Injectable()
export class LoginService {
authorised = false;
authorise(value) {
this.authorised = value;
}
}
// home.component.ts
import { Component } from '@angular/core';
import { LoginService } from './login.service';
@Component({
template: `
<h1>Home</h1>
<input #switch type="checkbox"
[checked]="loginService.authorised"
(click)="change(switch.checked)">
<div *ngIf="loginService.authorised">
<a>Today's best superheroe</a>
</div>`
})
export class Home {
constructor(private loginService:LoginService) { }
change(checked){
this.loginService.authorise(checked);
}
}
/users
[{
"id": 34,
"username": "spiderman",
"roles": ["admin", "user"]
}, {
"id": 67,
"username": "batman",
"roles": ["user"]
}]
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/retryWhen';
import 'rxjs/add/operator/delay';
@Injectable()
export class UsersService {
constructor(private http:Http) { }
get(){
return this.http.get('api/users.json')
.map(response => response.json())
.retryWhen(errors => errors.delay(2000));
}
}
import { Component } from '@angular/core';
import { UsersService } from './users.service';
@Component({
selector: 'users',
template: `
<h1>Users</h1>
<table class="table">
<tr *ngFor="let user of users">
<td>{{user.username}}</td>
</tr>
</table>`
})
export class Users {
constructor(private service:UsersService){
service.get().subscribe(users => this.users = users);
}
}
RouterModule.forRoot(routes)
RouterModule.forChild(routes)
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRouting } from './app.routing';
@NgModule({
imports: [ BrowserModule, AppRouting, ... ],
declarations: [ ... ],
providers: [ ... ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
/home
/users
/about
/users/34
// app.routing.ts
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: '**', component: NotFound }, //always last
];
export const AppRouting = RouterModule.forRoot(appRoutes, { useHash: true });
// app.component.ts
@Component({
selector: 'my-app',
template: `
<nav></nav>
<main>
<router-outlet></router-outlet>
</main>`
})
export class App { }
users
#/users
Users
users/:id
#/users/34
User
// users.routing.ts
import { Routes, RouterModule } from '@angular/router';
import { Users } from './users.component';
import { User } from './user.component';
const usersRoutes: Routes = [
{ path: 'users', component: Users },
{ path: 'users/:id', component: User }
];
export const UsersRouting = RouterModule.forChild(usersRoutes);
#/home
['home']
['users', 34] /users/:id
router.navigate(['users', 34])
router.navigateByUrl('/users/34')
import { Component } from '@angular/core';
@Component({
selector: 'users',
template: `
<h1>Users</h1>
<tr *ngFor="let user of users">
<td>
<a [routerLink]="['/users', user.id]">{{user.username}}</a>
</td>
</tr>
`
})
export class Users { }
<!-- Top Routes -->
<a href="#/home">Home</a>
<a [routerLink]="['home']">Home</a>
<!-- Nested Routes -->
<a href="#/users">Users</a>
<a [routerLink]="['users']">Users</a>
<a href="#/users/34">Spiderman</a>
<a [routerLink]="['users', 34]">Spiderman</a>
<!-- hash fragments -->
<a href="#/users/34#section">Spiderman</a>
<a [routerLink]="['users', 34]" fragment="section">Spiderman</a>
<!-- params and queryParams -->
<a href="#/users/34;flag=true?q=1">Spiderman</a>
<a [routerLink]="['users', 34, {flag: true}]" [queryParams]="{q: 1}">Spiderman</a>
// { path: 'users/:id', component: User } Url: #/users/34
import { Router } from '@angular/router';
@Component({
selector: 'user-details'
})
export class User implements OnInit {
constructor(private router: Router){ }
ngOnInit() {
console.log(this.router.url); // /users/34
}
}
// { path: 'users/:id', component: User } Url: #/users/34#section
import { Router } from '@angular/router';
@Component({
selector: 'user-details'
})
export class User implements OnInit {
constructor(private router: Router){
router.routerState.root.fragment.subscribe(f => {
let fragment = f; // section
});
}
ngOnInit() {
let fragment = this.router.routerState.snapshot.root.fragment; // section
}
}
// { path: 'users/:id', component: User } Url: #/users/34?q=1
import { Router } from '@angular/router';
@Component({
selector: 'user-details'
})
export class User implements OnInit {
constructor(private router: Router){
router.routerState.root.queryParams.subscribe(params => {
let q = params.q; // 1
});
}
ngOnInit() {
let q = this.router.routerState.snapshot.root.queryParams.q; // 1
}
}
// { path: 'users/:id', component: User, data: { key: 1 } }
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'user-details'
})
export class User implements OnInit {
constructor(private route: ActivatedRoute){
route.data.subscribe(data => {
let key = data.key; // 1
});
}
ngOnInit() {
let key = this.route.snapshot.data.key; // 1
}
}
// { path: 'users/:id', component: User } Url: #/users/34;flag=true
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'user-details'
})
export class User implements OnInit {
constructor(private route: ActivatedRoute){
route.params.subscribe(params => {
let id = params.id; // 34
});
}
ngOnInit() {
let id = this.route.snapshot.params.id; // 34
let flag = this.route.snapshot.params.flag; // true
}
}
// users.routing.ts
import { Routes, RouterModule } from '@angular/router';
import { UserCanDeactivate } from './user.canDeactivate';
const usersRoutes: Routes = [
{ path: 'users', component: Users },
{ path: 'users/:id', component: User,
canDeactivate: [UserCanDeactivate]
}
];
export const UsersRouting = RouterModule.forChild(usersRoutes);
// user.canDeactivate.ts
import { Injectable } from '@angular/core';
import { CanDeactivate } from '@angular/router';
Injectable()
export class UserCanDeactivate implements CanDeactivate {
canDeactivate() {
return window.confirm('Do you want to continue?');
}
}
// users.routing.ts
import { Routes, RouterModule } from '@angular/router';
import { AuthCanActivate } from './auth.canActivate';
const usersRoutes: Routes = [
{ path: 'users', component: Users },
{ path: 'users/:id', component: User,
canDeactivate: [UserCanDeactivate],
canActivate: [AuthCanActivate]
}
];
export const usersRouting = RouterModule.forChild(usersRoutes);
// auth.canActivate.ts
import { Injectable } from '@angular/core';
import { Router, CanActivate } from '@angular/router';
import { LoginService } from './login.service';
export class AuthCanActivate implements CanActivate {
constructor(private loginService: LoginService, private router: Router) {}
canActivate() {
if (!this.loginService.authorised) {
this.router.navigate(['/home']);
return false;
}
return true;
}
}
// app.routing.ts
const aboutRoutes: Routes = [
{ path: 'about', loadChildren: './app/about.module.ts' },
];
export const AboutRouting = RouterModule.forChild(aboutRoutes);
//about.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { AboutRouting } from './about.routing';
import { About } from './about.component';
@NgModule({
imports: [ CommonModule, AboutRouting ],
declarations: [ About ]
})
export default class AboutModule { }
// app.routing.ts
const routes: Routes = [
{path: 'home', component: HelloCmp},
{path: 'banner', component: Banner, outlet: 'bottom'}
];
// app.component.ts
@Component({
selector: 'my-app',
template: `
<router-outlet></router-outlet>
<router-outlet name="bottom"></router-outlet>`,
})
export class App { }
// templates/code
<a href="#/home(bottom:banner)">Show Banner!</a>
<a [routerLink]="['/home(bottom:banner)']">Show Banner!</a>
router.navigate('/home(bottom:banner)');
// about.routing.ts
import { Routes, RouterModule } from '@angular/router';
import { About } from './about.component';
import { AboutResolver } from './about.resolver';
const aboutRoutes: Routes = [
{ path: '', component: About,
resolve: { magicNumber: AboutResolver }
}
];
export const AboutRouting = RouterModule.forChild(aboutRoutes);
// about.resolver.ts
import { Injectable } from '@angular/core';
import { Resolve } from '@angular/router';
@Injectable()
export class AboutResolver implements Resolve {
resolve() {
console.log('Waiting to resolve...');
return new Promise(resolve => setTimeout(() => resolve(4545), 2000));
}
}
// about.component.ts
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'about',
template: `
<h1>About</h1>
<p>Magic Number: {{magicNumber}}</p>`
})
export class About {
magicNumber: number;
constructor(private route: ActivatedRoute){
this.magicNumber = route.snapshot.data.magicNumber;
}
}