Estou trabalhando em um aplicativo Angular onde busco dados de uma API e os exibo usando meu pipe de estado personalizado e pipe assíncrono. Há um botão para atualizar a chamada da API. No entanto, se ocorrer um erro, o observable para de emitir valores e não consigo mais atualizá-lo.
estado.pipe.ts
import { Pipe, PipeTransform } from '@angular/core';
import { Observable, catchError, map, of, startWith } from 'rxjs';
type ObsState<T> = Observable<ObsStateAsync<T>>;
export type ObsStateAsync<T> = { loading: boolean; result?: T; error?: any };
@Pipe({
name: 'state',
})
export class StatePipe implements PipeTransform {
transform<T>(val: Observable<T>): ObsState<T> {
return val.pipe(
map((value: any) => ({ loading: false, result: value })),
startWith({ loading: true }),
catchError((error) => of({ loading: false, error }))
);
}
}
@Component({
selector: 'app-root',
template: `
<button (click)="onRefresh()">Refresh</button>
@let breedState = breeds$ | state | async;
@if(breedState?.loading){
Fetching ...
}
@if(breedState?.error){
Error
}
@if(breedState?.result){
@for(breed of breedState?.result;track $index){
<div>
{{ breed.attributes.name }}
</div>
}
}
`,
imports: [StatePipe, AsyncPipe],
})
export class App {
private readonly httpClient = inject(HttpClient);
refresh = new BehaviorSubject<void>(undefined);
getBreed$ = this.httpClient
.get('https://dogapi.dog/api/v2/breeds') // Modify API endpoint to create an error
.pipe(map((res: any) => res.data));
breeds$ = this.refresh.asObservable().pipe(switchMap(() => this.getBreed$));
onRefresh(): void {
this.refresh.next();
}
}
E eu não quero fazer catchError(()=>of([]))
isso porque o erro precisa ser exibido na interface do usuário.
Você precisa colocar o
catchError
dentro do pipe do observable http, então eu sugiro umrxjs
operador de pipe reutilizávelstateTransform
que basicamente faz a mesma coisa, mas está dentro do pipe dohttp.get
.Você só precisa adicionar este operador reutilizável abaixo da
map
transformação.Código completo:
Demonstração do Stackblitz