Observable e a biblioteca RxJS em Angular
Os métodos da classe HttpClient
, após a execução de uma solicitação, retornam um objeto Observable<any>
, que é definido na biblioteca RxJS ("Reactive Extensions"). Embora não faça parte do Angular diretamente, essa biblioteca é amplamente utilizada, especialmente ao interagir com o servidor via HTTP. A RxJS implementa o padrão "observador assíncrono" (asynchronous observable), permitindo que as solicitações feitas ao servidor com a classe HttpClient
sejam realizadas de forma assíncrona. Isso significa que o código não é bloqueado enquanto a solicitação é processada, o que é especialmente útil em aplicações web.
Para utilizar as funcionalidades da RxJS na sua aplicação, é necessário instalar a biblioteca. Para isso, execute o seguinte comando no terminal:
npm install rxjs
Além disso, como foi mencionado no tema anterior, é necessário importar provideHttpClient
no arquivo main.ts
:
import { bootstrapApplication } from "@angular/platform-browser";
import { AppComponent } from "./app/app.component";
import { provideHttpClient } from "@angular/common/http";
bootstrapApplication(AppComponent, { providers: [provideHttpClient()] }).catch(
(err) => console.error(err)
);
Ao utilizar métodos especiais para o objeto Observable
, como map
e filter
, é possível realizar um processamento adicional dos resultados recebidos do servidor.
Por exemplo, vamos usar o projeto do tema anterior, com a seguinte estrutura:
helloapp/ ├── src/ │ ├── app/ │ │ ├── app.component.ts │ │ ├── user.ts │ ├── assets/ │ │ ├── data.json │ ├── main.ts │ ├── index.html ├── angular.json ├── package-lock.json ├── package.json └── tsconfig.json
No arquivo data.json
, podemos definir os dados de forma que não correspondam diretamente ao array de objetos User
:
{
"userList": [
{
"userName": "Bob",
"userAge": 28
},
{
"userName": "Tom",
"userAge": 39
},
{
"userName": "Alice",
"userAge": 32
}
]
}
Como modelo de dados, usaremos a classe User
, definida no arquivo user.ts
:
export class User {
constructor(public name: string, public age: number) {}
}
Nesse caso, não há correspondência direta entre os nomes das propriedades: name
e userName
, ou age
e userAge
.
No arquivo http.service.ts
, definimos o seguinte código para um serviço que vai obter os dados do arquivo data.json
:
import { Injectable } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { User } from "./user";
import { Observable } from "rxjs";
import { map } from "rxjs/operators";
@Injectable()
export class HttpService {
constructor(private http: HttpClient) {}
getUsers(): Observable<User[]> {
return this.http.get("assets/data.json").pipe(
map((data: any) => {
let usersList = data["userList"];
return usersList.map(function (user: any): User {
return new User(user.userName, user.userAge);
});
})
);
}
}
O propósito de usar um serviço especializado para lidar com HTTP é ocultar os detalhes do envio de requisições. O componente espera receber dados específicos, como uma coleção de objetos User
. Com o método map da RxJS, podemos transformar os dados recebidos de um formato para outro.
Após a execução do método get()
, podemos chamar o método pipe()
, que permite processar os resultados da solicitação. O método pipe recebe uma função como parâmetro, que processa os dados da requisição. Nesse caso, o operador map
desempenha esse papel, transformando os resultados em novos objetos.
Para usar os elementos da biblioteca RxJS, é necessário importá-los:
import { Observable } from "rxjs";
import { map } from "rxjs/operators";
No final, o método getUsers()
retorna um objeto Observable<User[]>
.
Agora, vamos utilizar o serviço no componente da aplicação:
import { Component, OnInit } from "@angular/core";
import { HttpService } from "./http.service";
import { User } from "./user";
@Component({
selector: "my-app",
standalone: true,
imports: [],
template: `<ul>
@for(user of users; track $index) {
<li>{{ user?.name }} ({{ user?.age }})</li>
}
</ul>`,
providers: [HttpService],
})
export class AppComponent implements OnInit {
users: User[] = [];
constructor(private httpService: HttpService) {}
ngOnInit() {
this.httpService.getUsers().subscribe({
next: (data: User[]) => (this.users = data),
});
}
}
Neste código, o serviço HttpService
é utilizado no componente AppComponent
para obter e exibir uma lista de usuários.