Servicios

El siguiente post es continuación del resumen de Angular 2

En el post anterior Modelo de datos y mocks cargábamos datos mocks importando directamente el archivo, esta no es la mejor forma debido a:

  • Necesitamos importar el archivo en cualquier archivo que necesite acceso a los datos.
  • No es sencillo cambiar el flujo de trabajo entre los datos reales y los mockeados.
  • La carga de datos la realizan mejor las clases de services.
Los servicios son utilizados para organizar y compartir código a través de toda la app, suelen organizarse:

example.component.ts (Pide datos al servicio) ->
example.service.ts (accede a los datos para pasarselos al componente) -> mocks.ts

Como por ejemplo:

  • example.service.ts

    1
    2
    3
    4
    5
    6
    import { CARPARTS } from './mocks';
    export class RacingDataService {
    getCarParts() {
    return CARPARTS;
    }
    }
  • example.component.ts

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    import { RacingDataService } from './racing-data.service';
    ...
    export class CarPartsComponent {
    carParts: CarPart[];
    ngOnInit() {
    let racingDataService = new RacingDataService();
    this.carParts = racingDataService.getCarParts();
    }
    }

De esta formar tenemos los datos desacoplados, no tenemos que importar los datos cuando nos sea necesario, solo el servicio y este es el que nos devuelve los datos, de esta forma si tenemos que cambiar la fuente de datos solo lo cambiamos en un solo lugar.

Los servicios en Angular 2 pueden y es conveniente usar el patrón de inyección de dependencias

El inyector de dependencias se encarga de crear y enviar los datos que le pidamos:

Sabe si es necesario instanciar los datos para enviarlos o enviar los ya instanciados.

Los pasos para hacer inyectable a un servicio son los siguientes:

  1. Añadir el decorator @inyectable al servicio.
  2. Indicar nuestro servicio inyectable en providers de @NgModule.
  3. Inyectar la dependencía en el componente que sea necesario.
  4. Utilizar el servicio en el componente en ngOnInit().

Por ejemplo:

  • 1.Añadir el decorator @inyectable al servicio.
1
2
3
4
5
6
7
8
9
import { CARPARTS } from './mocks';
import { Injectable } from '@angular/core';
@Injectable()
export class RacingDataService {
getCarParts() {
return CARPARTS;
}
}
  • 2.Indicar nuestro servicio inyectable en providers de @NgModule.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    ...
    import { RacingDataService } from './racing-data.service';
    @NgModule({
    declarations: [ AppComponent ],
    imports: [ BrowserModule, FormsModule ]
    bootstrap: [ AppComponent ] ,
    // En providers indicamos todos nuestros servicios inyectables
    providers: [ RacingDataService ]
    })
    class AppModule { }
    ...
  • 3y4 Inyectar la dependencía en el componente que sea necesario y utilizar el servicio en el componente en ngOnInit().

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    ...
    import { RacingDataService } from './racing-data.service';
    @Component({ ... })
    export class CarPartsComponent {
    carParts: CarPart[];
    // Inyectar la dependencia en el componente
    constructor(private racingDataService: RacingDataService) { }
    // Utilizarla
    ngOnInit() {
    this.carParts = this.racingDataService.getCarParts();
    }
    }

De esta forma conseguimos que nuestro servicio:

  • Sea desacoplado
  • Escalable porque nuestras dependencias están ligadas a las clases
  • Testeable porque es sencillo mockear

Two-way Binding

El siguiente post es continuación del resumen de Angular 2

En los posts anteriores hemos visto:

JavaScript to HMTL

HTML to JavaScript

Two-way Binding es la unión de ambos para tener una comunicación bidireccional, es posible hacerlo de dos formas:

  • Utilizando los dos Bindings:

    En este ejemplo en el mismo input se muestra la cantidad (Binding de propiedades) y se añade la cantidad (Binding de eventos):

1
<input class="number" type="text" [value]="carPart.quantity" (input)="carPart.quantity = $event.target.value">
  • Utilizando la síntasis [ () ] (Banana in the box)

Para ello en la clase del componente se importa @angular/forms:

1
2
3
4
5
6
7
8
9
10
11
...
import { FormsModule } from '@angular/forms';
@NgModule({
declarations: [ AppComponent ],
imports: [ BrowserModule , FormsModule ],
bootstrap: [ AppComponent ],
providers: [ RacingDataService ],
})
class AppModule { }
...

Y en el input se utiliza la síntasis [ () ]:

1
<input class="number" type="text" [(ngModel)]="carPart.quantity" >

De esta forma es mucho más clara y precisa.

Event Binding - Binding de eventos (One-Way Binding)

El siguiente post es continuación del resumen de Angular 2

En el post anterior se explicaba el (Binding de propiedades) el cual consistía en la comunicación de las propiedades de las clases de los componentes (TypeScript o JavaScript) al DOM, es decir:

JavaScript to HMTL

En el caso de Event Binding, es lo contrario:

HTML to JavaScript

Por ejemplo añadimos una función en nuestro componente:

1
2
3
4
5
6
export class CarPartsComponent {
...
upQuantity() {
alert("You Called upQuantity");
}
...

Y este es llamado desde HTML, por ejemplo al hacer click:

1
<button (click)="upQuantity( carPart )" >Click to alert</button>

Además del click tenemos los siguientes eventos:

1
2
3
4
5
6
7
8
9
<div (mouseover)="call()">
<input (blur)="call()">
<input (focus)="call()">
<input type="text" (keydown)="call()">
<form (submit)="call()">

Como es de esperar es posible coger información desde el elemento HTML para luego utilizarla en nuestra clase JS, por ejemplo vamos a mostrar un alert de cada letra que el usuario introduce en un input:

  • Código HTML:
1
<input type="text" (keydown)="showKey($event)">
  • TypeScript o JavaScript
export class CarPartsComponent {
  ...
  showKey(event) {
    alert(event.keyCode);
  }

  ...

En el siguiente post tratara de Two-way Binging, es decir comuncación bidireccional entre el DOM y Js.

Property Binding - Binding de propiedades y clases CSS (One-way binding)

El siguiente post es continuación del resumen de Angular 2

El Binding de propiedades significa mostrar las propiedades de nuesto componente en el DOM de la web y que cambie dinamícamente según cambía la propiedad, One-way binding es debido a que la comunicación es desde los modelos de los componentes de nuestra app al DOM no del DOM a la aplicación.

Con [ ] decimos a Angular 2 que esa propiedad del DOM va unida a una propiedad de nuestro modelo como por ejemplo:

  • <img [ src ] =" carPart.image ">
  • <div [ hidden ] ="!user.isAdmin" >secret</div>
  • <button [ disabled ] ="isDisabled" >Purchase</button>
  • <img [ alt ] ="image.description">

Binding Class (CSS)

También es posible hacer binding de una clase CSS dependiendo del modelo.

Por ejemplo la clase CSS

1
2
3
.featured {
background: #57595D;
}

Es posible añadirla dependiendo del modelo, en este caso de ejemplo cardPart.featured devuelve true o false y si es true se añade la clase .featured al elemento, está es la única síntasis posible:

<div [class.featured]="carPart.featured" >

Hay que tener en cuenta, que de esta forma cada elemento tiene su scope, el código generado sería el siguiente:

<div _ngcontent-opf-2 >

1
2
3
.featured[_ngcontent-opf-2] {
background: #57595D;
}

En definitiva:

  • El binding de propiedades permite hacer binding entre las propiedades del componente y el DOM.
  • Cualquier actualización del valor de la propiedad actualizara el DOM, pero no viceversa, una actualización del DOM no actualiza el modelo (One-way binding).
  • El binding de clases CSS nos permite especificar estilos a un elemento del DOM si la propiedad del componente es true, tienen su propio scope del estilo que es dado.

Modelos y uso de mocks

El siguiente post es continuación del resumen de Angular 2

Modelos en angular 2

Básicamente los modelos en angular 2 son clases como por ejemplo:

1
2
3
4
5
6
7
export class Carpart {
id: number;
name: string;
description: string;
inStock: number;
price: number;
}

De esta forma en la clase de nuestro componente podemos crear arrays de la clase Cardpart, importando la clase.

1
2
3
4
5
6
7
8
9
10
11
12
import { Component } from '@angular/core';
import { CarPart } from './car-part';
export class CarPartsComponent {
carParts: CarPart[] = [{
"id": 1,
"name": "Super Tires",
"description": "These tires are the very best",
"inStock": 5,
"price": 4.99
}, { ... }, { ... }]
...

Uso de mocks en angular 2

Una de las formas posibles para comenzar a desarrollar nuestra aplicación sin disponer aún los datos que nos va a suministrar la API es mediante Mocking (mockear datos).
Una forma simple es creando nuestro array de datos JSON o de clases que vayamos a utilizar y asignarlo a las propiedades de los componentes que nos sea necesario.

Como por ejemplo:

1
2
3
4
5
6
7
8
9
import { CarPart } from './car-part';
export const CARPARTS: CarPart[] = [{
"id": 1,
"name": "Super Tires",
"description": "These tires are the very best",
"inStock": 5,
"price": 4.99
}, { ... }, { ... }];

Y ahora en nuestro componente mediante la función ngOnInit() damos el valor a la propiedad correspondiente, en este ejemplo a la propiedad cardParts se le asigna el valor CARDPARTS el cual es el array de cardparts que hemos importado.

1
2
3
4
5
6
7
8
9
10
11
12
13
import { Component } from '@angular/core';
import { CarPart } from './car-part';
import { CARPARTS } from './mocks';
...
})
export class CarPartsComponent {
carParts: CarPart[] ;
ngOnInit() {
this.carParts = CARPARTS;
}
...

De esta forma podemos comenzar a desarrollar nuestra app con datos de prueba mocks ;).

Organización de código

El siguiente post es continuación del resumen de Angular 2

Organización de los componentes en Angular 2

Como vulgarmente se dice:

divide o vencéras

Partiendo del siguiente ejemplo en el que tenemos AppComponent en app/main.ts:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import { NgModule, Component } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
@Component({
selector: 'my-app',
template: `<h1> {{title}} </h1>
<h2>{{carPart.name}}<h2>
<p>{{carPart.description}}<p>
<p>{{carPart.inStock}} in Stock<p>`
})
class AppComponent {
title = 'Ultra Racing';
carPart = {
"id": 1,
"name": "Super Tires",
"description": "These tires are the very best",
"inStock": 5
};
}
@NgModule ({
declarations: [ AppComponent ]
})
class AppModule { }
platformBrowserDynamic()
.bootstrapModule(AppModule);

Movemos toda la parte del componente AppComponent a un fichero aparte como por ejemplo app.component.ts:

1
2
3
4
5
6
7
8
9
10
11
12
13
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
template: `<h1>{{title}}</h1>`
})
// Importante, exportar para utilizar el componente
export class AppComponent {
title = 'Ultra Racing';
carParts = [...];
totalCarParts() { ... };
}

Es importante, exportar para utilizar el componente export class..

En conclusión ahora disponeos de dos archivos:

  • main.ts Que importa el componente:
1
2
3
4
5
6
7
8
9
// Importante hacer el import
import { AppComponent } from './app.component';
@NgModule({
declarations: [ AppComponent ],
imports: [ BrowserModule ],
bootstrap: [ AppComponent ]
})
class AppModule { }
  • Y el propio componente en app.component.ts
1
2
3
4
5
6
7
8
9
10
11
12
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
template: `<h1>{{title}}</h1>`
})
export class AppComponent {
title = 'Ultra Racing';
carParts = [...];
totalCarParts() { ... };
}
Mover el código HTML CSS

Ahora procedemos a separar el código del template (html) y añadir los estilos,

Como por ejemplo en el componente anterior:

1
2
3
4
5
6
7
8
9
10
11
12
13
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: 'app/app.component.html',
styleUrls:['app/car-parts.component.css']
})
export class AppComponent {
title = 'Ultra Racing';
carParts = [...];
totalCarParts() { ... };
}

Como podemos observar el código HTML se encuentra en un archivo aparte app.component.html :

1
2
<p>There is a example ;).</p>
<ul>...</ul>

y el css en otro app.component.css :

1
2
3
4
5
6
7
.description {
color: #444;
font-size: small;
}
.price {
font-weight: bold;
}

De esta forma, nuestro componente se encuentra dividido en tres partes cada una en un archivo:

  • La lógica del componente en app.component.ts el cual se exporta para incluirlo en @module en main.ts.
  • El template con el html en app. component.html
  • Estilos del componente en app.component.css

Angular 2 - Estructura de directivas, Pipes y Métodos

Directivas

El siguiente post es continuación del resumen de Angular 2

Una directiva de Angular es la forma de añadir comportamiento dinámico a HTML mediante la etiqueta o selector que creamos.

Existen tres tipos diferentes de directivas:

Podemos verlas en el fragmento de código:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
...
@Component({
// El selector y templatte sería el primer tipo de directiva
selector: 'my-app',
template: `<h1>{{title}}</h1>
<ul>
<li *ngFor="let carPart of carParts">
<h2>{{carPart.name}}<h2>
<p>{{carPart.description}}<p>
<p *ngIf="carPart.inStock > 0">{{carPart.inStock}} in Stock</p>
<p *ngIf="carPart.inStock === 0">Out of Stock</p>
</li>
</ul>`
// En el propio template observamos las directivas de estructura *ngFor y *ngIf
})
class AppComponent {
...

Pipes y Métodos

Un pipe coge un dato de entrada y lo transforma a la salida deseada, como por ejemplo:

Métodos (Methods) como podemos imaginar es añadir métodos en la clase de nuestro componente para luego ser utilizada:

1
2
3
4
5
6
7
8
9
10
11
12
...
@Component({
selector: 'my-app',
template: `<h1>{{title}}</h1>`
})
class AppComponent {
exampleMethod() {
return 10;
}
}

Angular 2 - Primer componente Angular 2

El siguiente post es continuación del resumen de Angular 2

Para comenzar añadir en index.html el primer componente, llamado en este caso <my-app></my-app>

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html>
<head>
<!-- All the Angular 2 libraries needed -->
</head>
<body>
<my-app>Loading App ...</my-app>
</body>
</html>

Para cargar Js hay varias opciones, una de ellas es utilizar la librería SystemJS que se utiliza en el curso de codeschool:

El siguiente código añade el código de app/main.ts:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html>
<head>
<!-- All the Angular 2 libraries needed -->
<script>
System.import('app')
.catch(function(err){ console.error(err); });
</script>
</head>
<body>
<my-app>Loading App ...</my-app>
</body>
</html>

También una buena opción es con webpack como explican al detalle en la web oficial de angular.io.

En app/main.ts añadimos nuestro primer componente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import { NgModule, Component } from '@angular/core';
//Las siguientes dependencias son para renderizar en el navegador
import { BrowserModule } from '@angular/platform-browser';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
// Our component decorator code goes here:
@Component({
//la etiqueta añadida anteriormente <my-app></my-app>
selector: 'my-app',
// El contendio que se carga en nuestro componente
template: `<h1> {{title}} </h1>
<h2>{{carPart.name}}<h2>
<p>{{carPart.description}}<p>
<p>{{carPart.inStock}} in Stock<p>`
})
class AppComponent {
//Definimos las propiedades que usamos en el template con {{ }}
title = 'Ultra Racing';
carPart = {
"id": 1,
"name": "Super Tires",
"description": "These tires are the very best",
"inStock": 5
};
}
// El nuevo componente lo debemos declarar en el decorador @NgModucle
@NgModule ({
declarations: [ AppComponent ]
})
class AppModule { }
// Bootrasp app (Arrancar la aplicación)
platformBrowserDynamic()
.bootstrapModule(AppModule);

Tanto @Component como @NgModule son decorators, una feauture de typescript, explicado de forma breve digamos que “extiende” la funcionalidad o comportamiento de la clase a un objeto:

Resumen curso "Accelerating through ANGULAR 2" de CodeSchool

Al igual que en post Resumen de Flexbox en este post voy a realizar un esquema de los puntos
principales del curso Accelerating through ANGULAR 2 de CodeSchool, este resumen es más un mero esquema para recordar algunos aspectos importantes que una guía para aprender sobre el tema.

Para profundizar, recomendaría estos enlaces de cursos y fuentes:

También es necesario tener conocimientos TypeScript:

Contenido del curso: