THE AMAZING
by Gerard Sans (@gerardsans)
Google Developer Expert
Master of Ceremonies
International Speaker
Angular 2 Trainer
Community Leader
800
500
Some days before the conference...
Angular 2
Main Features
- Simple
- Fast
- Works everywhere
ES5 / ES6 / TypeScript
ES6 (ES2015)
- Classes, modules, arrow functions
TypeScript
- Types, annotations
- Better editor support
TypeScript IDE Support
Application Design
Component Tree
source: blog
/home
/users
/about
/users/34
Bootstrap
Bootstrapping
- Angular Application instantiation
- Root component (App)
-
Global Dependencies
- Router, Http, Services
- Global Values
- Vendor dependencies
index.html
<!DOCTYPE html>
<html>
<head>
<script src=".../system.js"></script>
<script src=".../typescript.js"></script>
<script src=".../angular2-polyfills.js"></script>
<script src=".../angular2.dev.js"></script>
<script src=".../http.js"></script>
<script src=".../router.js"></script>
<script src=".../Rx.js"></script>
<script>System.import('app');</script>
</head>
<body>
<my-app>
Loading...
</my-app>
</body>
</html>
Bootstrap
import {bootstrap} from 'angular2/platform/browser';
import {App} from './app';
import {HTTP_PROVIDERS} from 'angular2/http';
import {UsersService} from './usersService';
...
bootstrap(App, [
// Global dependencies
HTTP_PROVIDERS, ROUTER_PROVIDERS,
// App services
UsersService, LoginService, MenuService
])
.catch(err => console.error(err));
app.ts
import {Component} from 'angular2/core';
@Component({
selector: 'my-app',
template: `...`
})
export class App {
constructor() { }
}
Services
/home
/users
loginService.ts
import {Injectable} from 'angular2/core';
@Injectable()
export class LoginService {
authorised = true;
authorise(value) {
this.authorised = value;
}
}
home.ts
// home.ts
import {LoginService} from './loginService';
@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($event){
this.loginService.authorise($event);
}
}
/users
users.json
[{
"id": 34,
"username": "spiderman",
"roles": ["admin", "user"]
}, {
"id": 67,
"username": "batman",
"roles": ["user"]
}]
usersService.ts
import {Injectable} from 'angular2/core';
import {Http} from 'angular2/http';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/retryWhen';
@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));
}
}
usersList.ts
import {Component} from 'angular2/core';
import {UsersService} from './usersService';
@Component({
selector: 'users',
template: `
<h1>Users</h1>
<table class="table">
<tr *ngFor="#user of users">
<td>{{user.username}}</td>
</tr>
</table>`
})
export class UsersList {
constructor(private service:UsersService){
service.get().subscribe(users => this.users = users);
}
}
Setup Router
/home
/users
Location Strategies
- HashLocationStrategy
- Eg: #/home, #/users/34
- PathLocationStrategy (default)
- Requires
APP_BASE_HREF
- Eg: /home, /users/34
- Requires
Bootstrap
import {ROUTER_PROVIDERS} from 'angular2/router';
import {LocationStrategy, HashLocationStrategy} from 'angular2/router';
bootstrap(App, [
ROUTER_PROVIDERS,
provide(LocationStrategy, { useClass: HashLocationStrategy }),
])
/home
/users
/about
/users/34
Defining Routes
import {RouteConfig} from 'angular2/router';
import {Home} from './home';
import {Users} from './users';
import {AboutLazyLoader} from './aboutLazyLoader';
@RouteConfig([
{ path: '/home', component: Home, name: 'Home' },
{ path: '/users/...', component: Users, name: 'Users' },
{ path: '/about', loader: AboutLazyLoader , name: 'AboutLazyLoad' },
{ path: '/**', redirectTo: ['Home'] }
])
export class App { }
Outlets
import {Component} from 'angular2/core';
import {RouteConfig, ROUTER_DIRECTIVES} from 'angular2/router';
@Component({
selector: 'my-app',
template: `
<nav>...</nav>
<div>
<router-outlet></router-outlet>
</div>`,
directives: [ROUTER_DIRECTIVES]
})
@RouteConfig(...)
export class App { }
Users
/
UsersList
#/users, #/users/
:id
UserDetails
#/users/34
Child Routes
- Parent uses special mark
-
/users/...
-
- Child defines its own routes
- Always define a default route
-
useAsDefault: true
-
Child Routes
import {Component} from 'angular2/core';
import {RouteConfig, ROUTER_DIRECTIVES} from 'angular2/router';
import {UsersList} from './usersList';
import {UserDetails} from './userDetails';
@Component({
selector: 'users',
template: `<router-outlet></router-outlet>`,
directives: [ROUTER_DIRECTIVES]
})
@RouteConfig([
{ path: '/', component: UsersList, name: 'UsersList', useAsDefault: true },
{ path: ':id', component: UserDetails, name: 'UserDetails' },
])
export class Users { }
Navigation
- Using regular links with hash
-
#/home
-
- Using routerLink directive uses link DSL
-
['Home']
-
['/Users/UserDetails', {id: 34}]
-
- Programatically
-
router.navigate(['Home']);
-
router.navigateByUrl('/home');
-
routerLink
<!-- Top Routes -->
<a [routerLink]="['Home']">Home</a>
<a [routerLink]="['Users']">Users</a>
<a [routerLink]="['AboutLazyLoad']">About</a>
<!-- Nested Routes -->
<a [routerLink]="['/Users/UsersList']">Users</a>
<a [routerLink]="['/Users/UserDetails', {id: 34}]">Spiderman</a>
<a [routerLink]="['/Users/UserDetails', {id: 34, flag: true}]">Spiderman</a>
<!-- Relative Routes -->
<a [routerLink]="['./UsersList']">Users</a>
<a [routerLink]="['./UserDetails', {id: 34}]">Spiderman</a>
<a [routerLink]="['./UserDetails', {id: 34, flag: true}]">Spiderman</a>
Accessing Parameters
/*
{ path: ':id', component: UserDetails, name: 'UserDetails' }
*/
import {RouteParams} from 'angular2/router';
@Component({
selector: 'user-details'
})
export class UserDetails {
constructor(private params: RouteParams){
let id = params.get('id');
}
}
Navigation Features
Save changes
@Component({
selector: 'user-details'
})
export class UserDetails implements CanDeactivate {
routerCanDeactivate() {
return new Promise(resolve =>
resolve(window.confirm('Do you want to continue?'))
);
}
}
Block Access
@Component({
selector: 'user-details'
})
@CanActivate(next => {
let injector = appInjector();
let service = injector.get(LoginService);
return new Promise(resolve => {
resolve(service.authorised);
});
})
export class UserDetails { }
Navigation from users list to user details
- UsersList.routerCanDeactivate()
- UserDetails.@CanActivate()
- UsersList.routerOnDeactivate()
- UserDetails.routerOnActivate()
Lazy Loading
Setup
@RouteConfig([
{ path: '/about', loader: AboutLazyLoader , name: 'AboutLazyLoad' }
])
export class App { }
//aboutLazyLoader.ts
export function AboutLazyLoader(){
return System.import('./src/aboutLazyLoad.ts')
.then(module => module.AboutLazyLoad);
}
//aboutLazyLoad.ts
@Component({
selector: 'about',
template: `<h1>About</h1>`
})
export class AboutLazyLoad { }
Demo
Features
- PathLocationStrategy setup
- Nested routes with parameters
- Block leaving route
- Block route access
- SVG loading spinner
- Active menu css style fix
AngularConnect - Sept 27-28th
Danke schön!
The amazing Angular 2
By Gerard Sans
The amazing Angular 2
We don’t know when Angular 2 will be released but we know it’s going to be *AWESOME*. In this talk we are going to build a basic application while looking into different Angular 2 features like: bootstrapping, components, services, new template syntax and component routing.
- 8,277