Дополни мой комментарий, используя оператор nils . Мне нравится это решение, потому что оно «прозрачное», вижу, что вызов просто, например,
return this.httpClient.get('.....').pipe(
indicate(this.loading$))
Более того, Вы можете использовать любой наблюдаемый, а не только вызов http. Использование операторов rx js, например, для выполнения нескольких http-вызовов с использованием forkJoin, или использование switchMap для двух вызовов, в которых есть только канал, не перегружайте вызовы и не вызывайте щелчок
Оператор как
export const prepare = <T>(callback: () => void) => {
return (source: Observable<T>): Observable<T> =>
defer(() => {
callback();
return source;
});
};
export const indicate = <T>(indicator: Subject<boolean>) => {
let alive = true;
return (source: Observable<T>): Observable<T> =>
source.pipe(
prepare(() =>
timer(500)
.pipe(
takeWhile(() => alive),
take(1)
)
.subscribe(() => {
indicator.next(true);
})
),
finalize(() => {
alive = false;
indicator.next(false);
})
);
};
export const toClass = <T>(ClassType: { new(): T }) => (
source: Observable<T>
) => source.pipe(map(val => Object.assign(new ClassType(), val)));
Я поставил таймер, потому что я не хочу, чтобы отображалась «загрузка», если вызов не тратит более 500 миллисекунд
Сервис, подобный
export class DataService {
loading$ = new Subject<boolean>()
getData():Observable<any>
{
//one call, I simulate a simple response
//in general will be like this.httpClient.get(....)
const observable=of('New Data in'+new Date()).pipe(delay(1000))
return observable.pipe(
indicate(this.loading$))
}
}
У меня есть, например, в нашем app.component
<button (click)="loadData()">load</button>
{{data}}
<div *ngIf="(dataService.loading$ | async)">
loading...
</div>
И функция loadData
export class AppComponent {
data:any
//don't forget declare as public
constructor(public dataService:DataService){}
loadData()
{
this.dataService.getData().subscribe(res=>{
this.data=res
})
}
}
Обновление Что ж, я делаю, что $ loading принадлежит сервис, но вы можете сделать так, чтобы $ loading принадлежал компоненту, и использовать канал в компоненте
loading$ = new Subject<boolean>()
loadData2()
{
this.data="";
this.dataService.getData2().pipe(
indicate(this.loading$))
.subscribe(res=>{
this.data=res
})
}
<div *ngIf="(loading$ | async)">
loading...
</div>
. Вы можете увидеть в этот стек