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!