Introducción 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 nuevo router
el primer router (1.0) que salió se descartó y se empezó un nuevo desarrollo
el nuevo router 2.0 ya está deprecated y uno nuevo va a salir en breve
los siguientes ejemplos son basados en el nuevo router 3.0 aunque aún está en Beta
primero hay que decirle al router cómo tiene que crear las rutas
<html>
<head>
<base href="/">
<!-- more head tags -->
</head>
<body>
<!-- body content -->
</body>
</html>
añadir <base href="/"> en el head
ahora ya podemos configurar las rutas del router
import { Routes, RouterModule } from '@angular/router';
const appRoutes:Routes = [
{ path: 'crisis-center', component: CrisisCenterComponent },
{
path: 'heroes',
component: HeroListComponent,
data: {
title: 'Heroes List'
}
},
{ path: 'hero/:id', component: HeroDetailComponent },
{ path: '**', component: PageNotFoundComponent }
];
export const appRoutingProviders:any[] = [];
export const routing = RouterModule.forRoot(appRoutes);
crea tu aplicación con las rutas seleccionadas
import { AppComponent } from './app.component';
import { routing, appRoutingProviders } from './app.routing';
import { HeroListComponent } from './hero-list.component';
import { CrisisListComponent } from './crisis-list.component';
@NgModule({
imports: [ BrowserModule, FormsModule, routing ],
declarations: [ AppComponent, HeroListComponent, CrisisListComponent ],
providers: [ appRoutingProviders ],
bootstrap: [ AppComponent ]
})
ya puedes crear tu navegación
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
template: `
<h1 class="title">Component Router</h1>
<nav>
<a routerLink="/crisis-center" routerLinkActive="active"
[routerLinkActiveOptions]="{ exact: true }">Crisis Center</a>
<a routerLink="/heroes" routerLinkActive="active">Heroes</a>
<a routerLink="/crisis-center/admin" routerLinkActive="active">Crisis Admin</a>
<a routerLink="/login" routerLinkActive="active">Login</a>
</nav>
<router-outlet></router-outlet>
`
})
export class AppComponent {}
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!
Introducción a Angular 2
By Raúl Jiménez
Introducción a Angular 2
- 2,196