18 - Servicios: recuperación de datos de un servidor web

Hemos dicho en el concepto anterior que en Angular se delega todas las responsabilidades de acceso a datos (peticiones y envío de datos) y lógica de negocios en otras clases que colaboran con las componentes y son llamados servicios.

Veremos ahora como recuperar datos de un servidor web implementando dicha actividad en un servicio.

Problema

Confeccionar una aplicación que recupere una respuesta en JSON de la dirección:

http://scratchya.com.ar/vue/datos.php

La estructura del archivo JSON es:

[
  {
    "codigo": 1,
    "descripcion": "papas",
    "precio": 12.33
  },
  {
    "codigo": 2,
    "descripcion": "manzanas",
    "precio": 54
  }
]

Mostrar en una tabla HTML todos los artículos recuperados.

La recuperación de datos se debe hacer en un servicio.

  1. Desde la línea de comandos de Node.js procedemos a crear el proyecto013:

    f:\angularya> ng new proyecto013
    
  2. Crearemos el servicio que recuperará desde un servidor la lista de artículos

    f:\angularya\proyecto13\> ng generate service articulos --module=app
    

    Con el comando anterior estamos creando la clase 'ArticulosService' y lo estamos registrando en el módulo 'app' (recordemos que es el módulo que se crea por defecto)

    Se crean dos archivos y se modifica el archivo 'app.module.ts'.

    El código generado de la clase 'ArticulosService' es:

    import { Injectable } from '@angular/core';
    
    @Injectable()
    export class ArticulosService {
    
      constructor() { }
    
    }
    

    Lo modificamos por el siguiente código que permita recuperar desde un servidor web el archivo JSON:

    import { Injectable } from '@angular/core';
    import { HttpClient } from '@angular/common/http';
    
    @Injectable()
    export class ArticulosService {
    
      constructor(private http: HttpClient) { }
    
      retornar() {
        return this.http.get("http://scratchya.com.ar/vue/datos.php");
      }  
    
    }
    

    El archivo 'app.module.ts' se modifica con el siguiente código:

    import { BrowserModule } from '@angular/platform-browser';
    import { NgModule } from '@angular/core';
    
    import { AppComponent } from './app.component';
    import { ArticulosService } from './articulos.service';
    import {HttpClientModule} from '@angular/common/http';
    
    @NgModule({
      declarations: [
        AppComponent
      ],
      imports: [
        BrowserModule,
        HttpClientModule    
      ],
      providers: [ArticulosService],
      bootstrap: [AppComponent]
    })
    export class AppModule { }
    

    Se agrega en la propiedad 'providers' el nombre del servicio que acabamos de crear: 'AriculosService'.

    El responsabilidad del framework Angular de crear una instancia de todas las clases que definamos dentro de la propiedad 'providers'.

    También se importa la clase HttpClientModule.

  3. Ahora veremos como consumimos el servicio desde nuestra componente. Procedemos a modificar la componente que se crea por defecto 'AppComponent' que tiene por responsabilidad mostrar en la página el listado de artículos:

    import { Component, OnInit } from '@angular/core';
    import  { ArticulosService } from './articulos.service';
    
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent implements OnInit{
    
      private articulos = null;
    
      constructor(private articulosService: ArticulosService) {}
    
      ngOnInit() {
        this.articulosService.retornar()
          .subscribe( result =>  this.articulos = result)
      }
    }
    

    Primero importamos el servicio llamado ArticulosService que se almacena en el archivo 'articulos.service.ts':

    import { ArticulosService } from './articulos.service';
    

    Para inyectar el objeto de la clase 'ArticulosService' que crea Angular en forma automática lo hacemos en el parámetro del constructor:

      constructor(private articulosServicio: ArticulosService) {
      }
    

    Se almacena en el atributo 'articulosServicio' la referencia del objeto de la clase 'ArticulosService' que crea Angular.

    En el método ngOnInit actualizamos la propiedad 'articulos' con el resultado devuelto:

      ngOnInit() {
        this.articulosService.retornar()
          .subscribe( result =>  this.articulos = result)
      }
    

    Esta asignación dispara la actualización de la página HTML.

  4. Falta que codifiquemos la vista con los datos recuperados:

    app.component.html

    <div *ngIf="articulos!=null; else espera">
      <table border="1">
        <tr>
          <td>Codigo</td><td>Descripcion</td><td>Precio</td>
        </tr>
        <tr *ngFor="let art of articulos">
          <td>{{art.codigo}}</td>
          <td>{{art.descripcion}}</td>
          <td>{{art.precio}}</td>
        </tr>
      </table>
    </div>
    <ng-template #espera>Esperando datos...</ng-template>
    
  5. Si ejecutamos ahora el proyecto013 veremos en el navegador el listado de artículos, pero ahora recuperados de un servidor y no extraidos de un vector como en el concepto anterior:

    ng server -o