Estamos vivendo tempos difíceis com a epidemia do coronavírus. Assim, pode ser uma oportunidade para aprimorar habilidades e avançar nos estudos. #fiqueemcasa
A proposta deste artigo é construir uma aplicação Web em Angular 9 que consume dados da API COVID19.
Abaixo, como ficará a aplicação.
Se preferir, escrevi um tutorial dessa mesma API com Flutter. O tutorial e o código estão aqui.
Passos iniciais
Caso você seja iniciante no framework, recomendo o link para criação do projeto.
Após a construção, vamos importar o módulo HttpClientModule no módulo principal da aplicação.
No arquivo app.module ts, realize o import e a assinatura no array de imports:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule} from '@angular/common/http';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule,
HttpClientModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Codificando as classes
Vamos criar o modelos que mapeia os dados relacionados as informações gerais da pandemia.
Dentro da pasta app, crie a pasta models e o arquivo mundo.model.ts.
export interface Mundo {
cases : number;
deaths : number;
recovered : number;
affectedCountries : number;
updated : number;
}
Mapeamos as informações relacionadas aos números de infectados, mortes, quantidade de países afetados e a última atualização.
Vamos criar em seguida o model que representa os casos do país, já que a API traz informações específicas de cada lugar.
Na mesma pasta, crie o arquivo pais.model.ts
import { Mundo } from './mundo.model';
export interface Pais extends Mundo {
country: string;
todayDeaths: number;
critical: number;
casesPerOneMillion: number
deathsPerOneMillion: number;
countryInfo: CountryInfo;
}
interface CountryInfo {
flag: string;
}
Utilizando um pouco de orientação a objetos, na assinatura da criação da interface herdamos a interface Mundo com extends, já que há campos em comum.
Declaramos os atributos específicos do país como o nome, número de mortos do dia, números de pessoas internadas em estado crítico, além de um objeto aninhado, CountryInfo, que retorna uma imagem da bandeira.
Criando o serviço
Vamos criar o serviço que acessa o endpoint da API e métodos.
No terminal, informe o comando:
ng g service services/covidapi
Vamos editar o arquivo covidapi.service.ts que se encontra na pasta services.
O código será:
import { Pais } from './../models/pais.model';
import { Mundo } from './../models/mundo.model';
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Injectable({
providedIn: 'root'
})
export class CovidapiService {
url = 'https://corona.lmao.ninja/v2'
constructor(private http: HttpClient) { }
async getInfoMundo() {
return await this.http.get<Mundo>(`${this.url}/all`)
.toPromise()
.then(mundo => {return mundo});
}
getInfoPais(pais: string = 'brazil') {
return this.http.get<Pais>(`${this.url}/countries/${pais}`)
.toPromise()
.then(pais => {return pais})
}
}
Definimos o endpoit da API no atributo url.
Fazemos a injeção de HttpClient no método construtor para requisitar chamadas na API. Em seguida, codificamos o método getInfoMundo. Como o operador get, tipando o retorno com a interface criada <Mundo>, informando a url e concatenada com ‘/all’.
Dessa forma, as informações gerais do pandemia.
Na sequência, usamos o método toPromise() e no callback retorno o objeto.
A promise é uma abstração para representar fluxos de ações em códigos assíncronos, processando um único evento quando uma operação assíncrona é concluída ou falha.
Nesse outro artigo aqui, eu invoco também uma api, mas usando Observables.
No método getInfoPais(), escrevo um parâmetro pais e defino um valor padrão brasil, caso nenhum seja informado. A diferença está na chamada da requisição, concatenando com a string ‘/countries/${pais}’, para acessar informações específicas do país informado.
Componente e View principal
Vamos editar o componente principal, mas antes instalaremos a biblioteca sweetalert2.
No terminal informe:
npm install sweetalert2.
Abra o arquivo app.component.ts e codifique assim:
import { Pais } from './models/pais.model';
import { Mundo } from './models/mundo.model';
import { CovidapiService } from './services/covidapi.service';
import { Component, OnInit } from '@angular/core';
import Swal from 'sweetalert2';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
mundo: Mundo;
pais: Pais;
constructor(private apiService: CovidapiService) {}
async ngOnInit(){
this.mundo = await this.apiService.getInfoMundo();
this.pais = await this.apiService.getInfoPais();
}
async trocaPais(){
const { value: inputPais } = await Swal.fire({
title: 'Informe um País:',
input: 'text',
inputPlaceholder: 'País'
})
if (inputPais) {
this.pais = await this.apiService.getInfoPais(inputPais)
}
}
}
Declaramos as interfaces mundo e pais e no construtor, realizamos a injeção de dependência do serviço codificado no passo anterior.
No método ngOnInit, chamamos os métodos com o operador await bindando as interfaces no carregamento inicial no componente.
Finalmente o método trocaPais, apresenta um dialog com um input. Se existir valor, passamos no parâmetro do método getInfoPais.
Não esqueça de apagar todo o conteúdo existente em app.component.html, gerado na construção do projeto.
Abaixo, um trecho inicial do código. O código do template, assim como do projeto está disponível no meu Github, no final do artigo.
<div class="container py-3">
<div ngIf="mundo">
<div class="row table-dark m-2 round text-center">
<h2 class="text-white mx-auto ">COVID-19 </h2>
<h3 class="text-white mx-auto"> Informações Gerais </h3>
<p class="mx-auto"> Atualizado em {{(mundo.updated | date : 'dd/MM/yy HH:mm')}} </p>
</div>
<!-- Formacoes Gerais-->
<div class="row ">
<div class="col-md-12">
<div class="card-counter info">
<i class="fa fa-users fa-3x"></i>
<span class="count-numbers">{{mundo.cases}}</span>
<span class="count-name">TOTAL DE CASOS MUNDO</span>
</div>
</div>
Para prevenir-se de erros de renderização, utilizamos uma diretiva estrutural *ngIf para verificar a existência do objeto.
No campo da atualização, eu informo um Pipe para transformar em data, especificando um formato ‘dd/MM/yy HH:mm’.
Se tiver alguma dúvida, deixe no comentários.
Se cuidem, e que Deus nos proteja.
Veja aqui o link do repositório