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...

algunos links útiles

 

angular.io

Angular 2 Bible

Thoughtram

¡GRACIAS!