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
    import { CARPARTS } from './mocks';
    export class RacingDataService {
      getCarParts() {
        return CARPARTS;
      }
    }
    
  • example.component.ts

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

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

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

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

...
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 [ () ]:

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

export class CarPartsComponent {
  ...
  upQuantity() {
    alert("You Called upQuantity");
  }
  ...

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

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

Además del click tenemos los siguientes eventos:

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

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

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

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.

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:

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.

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