actualízate a
Angular 2
Raúl Jiménez
@elecash
sobre mí
Angular GDE
videogular
google partner
toptal partner
hablemos de javascript
estoy contento con mi framework actual
¿por qué debería utilizar Angular2?
mobile first · pensado para durar · rendimiento · simple · expresivo · inmutables · animaciones · DI jerárquica · web components · a11y · renderizado en servidor · i18n · rxjs · TypeScript · web workers · etc...
supongo que ahora ya estás convencido
cómo funciona angular2
tu aplicación es un árbol de componentes
Application es un componente
import {Component} from '@angular/core';
@Component({
/* configuration */
})
class Application {
/* ... */
}
Application contiene Toolbar
Application contiene Toolbar
// application.ts
import {Component} from '@angular/core';
import {Toolbar} from './components/toolbar/toolbar';
@Component({
selector: 'my-root'
template: `<my-toolbar></my-toolbar>`,
directives: [ Toolbar ]
})
export class Application { /* ... */ }
<!-- index.html -->
<my-root>
Your application is loading...
</my-root>
todos los componentes tienen un ciclo de vida
arrancamos la aplicación para nuestra plataforma
import {Component} from '@angular/core';
import {bootstrap} from '@angular/platform-browser-dynamic';
@Component({
/* configuration */
})
class Application {
/* ... */
}
bootstrap(Application, [ /* deps */ ])
capturamos cuando se crea un componente con ngOnInit
import {Component, OnInit} from '@angular/core';
@Component({
/* configuration */
})
class Application implements OnInit {
/* ... */
ngOnInit() { /* ... */ }
}
ciclo de vida entero de un componente
class Application {
ngOnInit() {}
ngOnDestroy() {}
ngDoCheck() {}
ngOnChanges(changes) {}
ngAfterContentInit() {}
ngAfterContentChecked() {}
ngAfterViewInit() {}
ngAfterViewChecked() {}
}
todos los componentes tienen un template
los decorators añaden expresividad a tus clases
import {Component} from '@angular/core';
@Component({
selector: 'my-toolbar',
templateUrl: 'comps/toolbar/toolbar.html',
styleUrls: ['comps/toolbar/toolbar.css']
})
class Toolbar {
isOpen:boolean = false;
user:string = null;
/* ... */
}
bindings unidireccionales
<!-- comps/toolbar/toolbar.html -->
<div [ngClass]="{active: isOpen, disabled: !isOpen}">
<div *ngIf="user">Hello {{ user }}.</div>
<div *ngIf="!user">Login</div>
</div>
bindings de propiedades con @input()
<!-- application.html -->
<my-toolbar [isOpen]="isToolbarOpen"></my-toolbar>
import {Component, Input} from '@angular/core';
@Component({
selector: 'my-toolbar',
templateUrl: 'comps/toolbar/toolbar.html',
styleUrls: ['comps/toolbar/toolbar.css']
})
class Toolbar {
@Input() isOpen:boolean = false;
user:string = null;
/* ... */
}
capturar eventos con (event)
<!-- comps/toolbar/toolbar.html -->
<div [ngClass]="{active: isOpen, disabled: !isOpen}">
<div *ngIf="user">Hello {{ user }}.</div>
<div *ngIf="!user" (click)="onClickLogin()">Login</div>
</div>
import {Component, Input} from '@angular/core';
@Component({/* ... */})
class Toolbar {
@Input() isOpen:boolean = false;
user:string = null;
onClickLogin() {
/* ... */
}
}
emitir eventos con @Output()
<!-- application.html -->
<my-toolbar [isOpen]="isToolbarOpen"
(onClickLogin)="doSomethingOnApp()">
</my-toolbar>
import {Component, Input, Output, EventEmitter} from '@angular/core';
@Component({/* ... */})
class Toolbar {
@Input() isOpen:boolean = false;
@Output('onClickLogin') onClickLogin:EventEmitter<any> = new EventEmitter();
user:string = null;
onClickLogin() {
this.onClickLogin.next(event.target);
}
}
bindings de dos direcciones con [(ngModel)]
<!-- comps/toolbar/toolbar.html -->
<div [ngClass]="{active: isOpen, disabled: !isOpen}">
<div *ngIf="user">Hello {{ user }}.</div>
<div *ngIf="!user">
<input type="text" [(ngModel)]="username">
<input type="password" [(ngModel)]="password">
<div (click)="onClickLogin()">Login</div>
</div>
</div>
¿Y LAS DIRECTIVAS?
SORPRESA
los componentes son directivas que tienen un template
lo cierto es que hay tres tipos de directivas
components
<my-toolbar></my-toolbar>
import {Component} from '@angular/core';
@Component({
selector: 'my-toolbar',
templateUrl: 'comps/toolbar/toolbar.html',
styleUrls: ['comps/toolbar/toolbar.css']
})
class Toolbar {
/* ... */
}
directivas estructurales
<my-card
*ngIf="isFooBar"
*ngFor="let card of dataStore.items;
trackBy:customTrackBy">
{{ card }}
</my-card>
<!-- es equivalente a esto -->
<template
ngFor
let-card
[ngForOf]="dataStore.items"
[ngForTrackBy]="customTrackBy">
<my-card>{{ card }}</my-card>
</template>
attributes
<my-progress-bar [style.width]="progress + '%'">
<span [blink]>{{ card + '%' }}</span>
</my-progress-bar>
import {Component} from '@angular/core';
@Component({
selector: '[blink]'
})
class Blink {
/* ... */
}
no lo llames filters llámalo pipes
los pipes son parecidos a los filters de Angular 1.X
DatePipe
UpperCasePipe
LowerCasePipe
CurrencyPipe
PercentPipe
etc...
los pipes son parecidos a los filters de Angular 1.X
<span>{{ username | trim }}</span>
import {Pipe, PipeTransform} from '@angular/core';
@Pipe({
name: 'trim'
})
export class TrimPipe implements PipeTransform {
transform(value: any) {
if (!value) {
return '';
}
return value.trim();
}
}
el nuevo deprectated router
el nuevo router que se desarrolló ya está deprecated y uno nuevo va a salir en breve
los siguientes ejemplos son basados en el router deprecated ya que el nuevo aún no es estable
para usar el router has de incluirlo en el bootstrap como una dependencia
import {provide} from '@angular/core';
import { bootstrap } from '@angular/platform-browser-dynamic';
import {AppComponent} from './app.component';
import {
ROUTER_PROVIDERS,
PathLocationStrategy,
LocationStrategy // or HashLocationStrategy
} from '@angular/router-deprecated';
bootstrap(AppComponent, [
ROUTER_PROVIDERS,
provide(LocationStrategy, {
useClass: PathLocationStrategy // or HashLocationStrategy
})
]);
ya puedes asignar rutas a tus componentes
import { ROUTER_DIRECTIVES, RouteConfig } from '@angular/router-deprecated';
@Component({
selector: 'app',
template: `
<h1>Component Router</h1>
<nav>
<a [routerLink]="['Customers']">Customers</a>
<a [routerLink]="['Orders', {id: order.id}]">Orders</a>
</nav>
<router-outlet></router-outlet>
`,
directives: [ROUTER_DIRECTIVES]
})
@RouteConfig([
{ path: '/', name: 'Customers', component: CustomersComponent, useAsDefault: true },
{ path: '/orders/:id', name: 'Orders', component: OrdersComponent },
{ path: '/details/...', name: 'OrderDetails', component: DetailsComponent }
])
export class AppComponent {
constructor(private params: RouteParams) {
let id = this.params.get('id');
}
}
providers
factories
services
factories y services ya no existen, ahora solo hay providers
import { Component } from '@angular/core';
import { DataStore } from './my-store';
@Component({
selector: 'home',
providers: [ DataStore ],
//...
})
export class Home {
private data: any[];
constructor(data: DataStore){
this.data = data.someAPI();
}
}
los providers son clases inyectables
import {Injectable} from 'angular2/core';
@Injectable()
export class DataStore {
constructor() {}
someAPI() {
// ...
}
}
puedes configurar tus providers para que usen otras clases
import { Component, provide } from '@angular/core';
import { DataStore } from './my-store';
@Component({
providers: [ provide(DataStore, {useClass: MockedDataStore}) ]
})
export class Home { /* */ }
y muchas cosas más que no tengo tiempo de explicar
inmutables · testing ·
animaciones · i18n ·
DI jerárquica · a11y ·
web components ·
renderizado en servidor · rxjs · web workers · CLI · formularios · etc...
¡GRACIAS!
Actualízate a Angular 2
By Raúl Jiménez
Actualízate a Angular 2
- 1,737