Atualizando o exemplo de AngularJS – parte 3

exemploAngular-3_abertura

Continuando com a tarefa de conversão do exemplo em AngularJS para Angular. Na parte anterior, do ponto de vista funcional, ela foi concluída, ou seja, agora ambos os exemplos exibem o mesmo resultado porém a versão em Angular utilizava um objeto JavaScript para receber as notas, ao invés de baixá-las via HTTP.

Nesta parte a implementação de um serviço para acessar o servidor web, baixar os dados e transferi-los corretamente para o componente.

(Re)iniciando a aplicação

Aproveitando que agora há um repositório git contendo a aplicação para (re)fazer tudo¹ do jeito certo.

$ git clone git@github.com:plainspooky/exemploAngular.git
Cloning into 'exemploAngular'...
...
$ cd exemploAngular
$ npm install
...
Testing binary
Binary is fine
...
added 1496 packages from 1658 contributors in 36.492s
$ export PATH=$( npm bin ):$PATH

Para clonar o repositório, baixar e instalar as dependências e…

$ ng serve --open
** Angular Live Development Server is listening on localhost:4200,
open your browser on http://localhost:4200/ *

Iniciar o servidor HTTP do Angular.

(¹) Justamente como se isto aqui fosse um “projeto sério”! 😀

Criando um serviço

exemploAngular-3_service

Agora, ao invés de colocar um objeto contendo as notas dentro do componente “grade” vamos fazer com que ele recupere de outra fonte, para isto é necessário criar um serviço.

$ cd src/app/grade
$ ng generate service grades
CREATE src/app/grade/grades.service.spec.ts (338 bytes)
CREATE src/app/grade/grades.service.ts (136 bytes)

Como este serviço, o “grades” é específico de “grade”, preferi criá-lo dentro da estrutura do componente mesmo.

Dentro do arquivo “grades.service.ts”, algumas pequenas modificações…

import { Injectable } from '@angular/core';

@Injectable({
   providedIn: 'root'
})

export class GradesService {

  constructor() { }

  getGrades () {
    return [{nome:"Adão Nogueira",
             notas:[9.89, 8.75, 6.34, 8.05]}]
  }
}

Basicamente foi criado um método para retornar os dados e como isto é apenas um teste, contém apenas um aluno. E o arquivo “grade.component.ts” também precisa de alterado para saber usar o serviço.

import { Component, OnInit } from '@angular/core';
import { GradesService } from './grades.service';
...
export class GradeComponent implements OnInit {
  ...
  alunos = []

  constructor(private gradesService: GradesService) {}

  ngOnInit() {
    this.alunos = this.gradesService.getGrades()
  }
  ...
}

Ou seja, ele “injeta” o serviço dentro da classe e permitindo assim que ele seja utilizado dentro da classe.

Incrementando o serviço

Por enquanto esta alteração é apenas um versão sofisticada da primeira implementação, o componente não tem mais dados estáticos dentro dele e que é provido por um serviço externo, porém os dados ainda continuam dentro do código.

A primeira coisa é salvar o arquivo JSON em algum lugar do servidor de testes do Angular que é acessível ao navegador web, o diretório “./assets”. Só para garantir que está tudo funcionando…

$ curl 127.0.0.1:4200/assets/grades.json
[{
    "id": 1,
    "nome": "Adão Nogueira",
    "notas": [9.89, 8.75, 6.34, 8.05]
}, {
    "id": 2,
    "nome": "Bruno Tavares",
    "notas": [6.32, 8.25, 7.67, 7.97]
}, {
    "id": 3,
    "nome": "João da Silva",
    "notas": [5.1, 5.22, 7.33, 8]
}, {
    "id": 4,
    "nome": "José Queiroz",
    "notas": [9.31, 7.9, 8, 8.832]
}]

Aproveitei para incluir uma chave de “ID” dentro dos dados (não usarei, apenas deixei com cara de banco de dados).

Para que o Angular possa acessar os dados via HTTP é necessário carregar o módulo HttpClient na aplicação. Isto é feito editando o arquivo “app.module.ts”:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';

import { AppComponent } from './app.component';
import { GradeComponent } from './grade/grade.component';

@NgModule({
  declarations: [
    AppComponent,
    GradeComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule
  ],
  ...
})
export class AppModule { }

Para fazer as coisas do jeito certo, é necessário criar uma interface para descrever os dados que serão carregados, o arquivo “grade.ts”:

export interface Grade {
  id: number;
  nome: string;
  notas: number[];
}

Isto é, um campo de “id” com dados numéricos, um campo “nome” que é uma string e “notas” contendo uma lista de números.

Então fazer algumas modificações no serviço criado agora a pouco…

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

import { Grade } from './grade';

@Injectable({
  providedIn: 'root'
})

export class GradesService {

  private gradesUrl = 'assets/grades.json';

  constructor(private http: HttpClient) {
  }

  public getGrades() {
    return this.http.get<Grade[]>(this.gradesUrl);
  }
}

Basicamente o ele recebe o módulo HttpClient, a descrição da interface, uma variável contendo a URL onde se encontra o arquivo JSON e, por último, o método getGrades() é alterado para retornar um array de notas via protocolo HTTP.

Voltando para o componente “grade”, também são necessários alguns ajustes para que ele consiga acessar corretamente os dados vindos do serviço…

import { Component, OnInit } from '@angular/core';
import { Grade } from './grade';
import { GradesService } from './grades.service';
...

export class GradeComponent implements OnInit {
  ...
  ngOnInit() {
    this.getGrades()
  }

  getGrades() {
    this.gradesService.getGrades()
      .subscribe((data: Grade[]) => this.alunos = data)
  }
  ...
}

Este método, o getGrades(), “assinará” o serviço “grades”, receberá os dados e os colocará dentro da variável correta (repare que o componente também recebeu a descrição da interface).

Montando a aplicação

Diferente do que acontecia com o AngularJS é necessário “montar” a aplicação para que ela possa ser executada fora do servidor de testes…

$ ng build
Date: 2019-03-31T18:30:09.956Z
Hash: 733655e62cdcae3a37be
Time: 9445ms
chunk {es2015-polyfills} es2015-polyfills.js, es2015-polyfills.js.map (es2015-polyfills)
284 kB [initial] [rendered]
chunk {main} main.js, main.js.map (main) 14.8 kB [initial] [rendered]
chunk {polyfills} polyfills.js, polyfills.js.map (polyfills) 236 kB [initial] [rendered]
chunk {runtime} runtime.js, runtime.js.map (runtime) 6.08 kB [entry] [rendered]
chunk {styles} styles.js, styles.js.map (styles) 16.5 kB [initial] [rendered]
chunk {vendor} vendor.js, vendor.js.map (vendor) 3.28 MB [initial] [rendered]

Isto converterá o código de TypeScript para JavaScript e produzirá uma versão de distribuição do programa para ser instalado em um servidor HTTP. Inclusive é até possível “testá-la”…

$ python3 -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
127.0.0.1 - - [31/Mar/2019 15:46:19] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [31/Mar/2019 15:46:19] "GET /runtime.js HTTP/1.1" 200 -
127.0.0.1 - - [31/Mar/2019 15:46:19] "GET /polyfills.js HTTP/1.1" 200 -
127.0.0.1 - - [31/Mar/2019 15:46:19] "GET /styles.js HTTP/1.1" 200 -
127.0.0.1 - - [31/Mar/2019 15:46:19] "GET /vendor.js HTTP/1.1" 200 -
127.0.0.1 - - [31/Mar/2019 15:46:19] "GET /main.js HTTP/1.1" 200 -
127.0.0.1 - - [31/Mar/2019 15:46:20] "GET /assets/grades.json HTTP/1.1" 200 -
127.0.0.1 - - [31/Mar/2019 15:46:20] "GET /favicon.ico HTTP/1.1" 200 -

Claro, o servidor web embutido no Python não é bem um “ambiente produção” mas é suficiente para verificar que está tudo funcionando perfeitamente (inclusive as notas sendo recuperadas diretamente do arquivo JSON).

Conclusão

Para ajudar, no repositório git as duas versões do programa nesta parte estão separados em duas tags:

  • “parte_3”, com a implementação do serviço com dados estáticos e
  • “parte_3_http”, com o serviço baixando os dados de um JSON via HTTP.

Assim está concluída a conversão do exemplo de AngularJS para o Angular. Um bom exercício para se fazer é aumentar a quantidade de alunos no JSON e também fazer as alterações necessárias para o ID também seja exibido na página web.

Até!

Anúncios

Um comentário sobre “Atualizando o exemplo de AngularJS – parte 3

  1. Pingback: Decoradores em Python | giovannireisnunes

Os comentários estão desativados.