在 Angular7 中的 HTTP 请求期间显示微调器
Showing a spinner during HTTP requests in Angular7
我试图在 Angular 7 上的应用程序的 HTTP 请求期间显示微调器。
我已经创建了一个 HttpInterceptor class、一个加载器服务和一个加载器组件以及一个表示微调器状态(显示或隐藏)的 Subject。但是加载器服务和加载器组件之间似乎存在问题
HttpInterceptor 似乎工作正常,因为控制台输出 true 和 false 状态(下面的代码),但是加载程序服务和加载程序组件似乎有问题。我使用 ngIf 指令根据 Subject 的状态显示或隐藏微调器。
加载服务:
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class LoaderService {
isLoading = new Subject<boolean>();
show() {
console.log('true');
this.isLoading.next(true);
}
hide() {
console.log('false');
this.isLoading.next(false);
}
constructor() { }
}
LoaderComponent
import { Component, OnInit } from '@angular/core';
import {LoaderService} from '../loader.service';
import { Subject } from 'rxjs';
@Component({
selector: 'app-loader',
templateUrl: './loader.component.html',
styleUrls: ['./loader.component.css']
})
export class LoaderComponent implements OnInit {
isLoading: Subject<boolean> = this.loaderService.isLoading;
constructor(private loaderService: LoaderService) { }
ngOnInit() {
}
}
<div *ngIf="isLoading | async " class="d-flex justify-content-center">
<div class="spinner-border" role="status">
<span class="sr-only">Loading...</span>
</div>
</div>
目前微调器根本没有显示或隐藏。我只在加载开始时在控制台中得到 'true',然后在加载结束时得到 'false'。
我已将加载器选择器包含在 app.component.html 文件中。它应该工作正常。我是不是做错了什么?
您应该使用 BehaviourSubject
而不是 Subject
。 Subject
仅在调用 next()
时发出值 - 如果在服务推送值后初始化组件,则不会收到任何内容。
BehaviourSubject
通过记住最后发出的值来解决这个问题。因此,当您的模板订阅时,它可以获得最后一个值并进行比较。
创建一个可以发出 HTTP 请求的布尔状态的 HttpInterceptor
非常棘手。可以同时发生多个并行请求,这并不像为每个 HttpRequest
发出 true/false 那么简单。您只需要在请求开始时发出 true 一次,而在 last 请求完成时发出 false 。
最简单的方法是跟踪并发请求数。
这是我使用的拦截器。它仅在启动新请求时发出 true,并且仅在所有请求完成时发出 false。
import {HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from '@angular/common/http';
import {Injectable} from '@angular/core';
import {Observable, Subject} from 'rxjs';
import {distinctUntilChanged, finalize, map} from 'rxjs/operators';
class BusySubject extends Subject<number> {
private _previous: number = 0;
public next(value: number) {
this._previous += value;
if (this._previous < 0) {
throw new Error('unexpected negative value');
}
return super.next(this._previous);
}
}
@Injectable()
export class BusyInterceptor implements HttpInterceptor {
private _requests: BusySubject = new BusySubject();
public get busy(): Observable<boolean> {
return this._requests.pipe(
map((requests: number) => Boolean(requests)),
distinctUntilChanged(),
);
}
public intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
this._requests.next(1);
return next.handle(req).pipe(finalize(() => this._requests.next(-1)));
}
}
p.s. This could properly be done using a scan() operator, but I haven't had time to update the code.
我试图在 Angular 7 上的应用程序的 HTTP 请求期间显示微调器。 我已经创建了一个 HttpInterceptor class、一个加载器服务和一个加载器组件以及一个表示微调器状态(显示或隐藏)的 Subject。但是加载器服务和加载器组件之间似乎存在问题
HttpInterceptor 似乎工作正常,因为控制台输出 true 和 false 状态(下面的代码),但是加载程序服务和加载程序组件似乎有问题。我使用 ngIf 指令根据 Subject 的状态显示或隐藏微调器。
加载服务:
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class LoaderService {
isLoading = new Subject<boolean>();
show() {
console.log('true');
this.isLoading.next(true);
}
hide() {
console.log('false');
this.isLoading.next(false);
}
constructor() { }
}
LoaderComponent
import { Component, OnInit } from '@angular/core';
import {LoaderService} from '../loader.service';
import { Subject } from 'rxjs';
@Component({
selector: 'app-loader',
templateUrl: './loader.component.html',
styleUrls: ['./loader.component.css']
})
export class LoaderComponent implements OnInit {
isLoading: Subject<boolean> = this.loaderService.isLoading;
constructor(private loaderService: LoaderService) { }
ngOnInit() {
}
}
<div *ngIf="isLoading | async " class="d-flex justify-content-center">
<div class="spinner-border" role="status">
<span class="sr-only">Loading...</span>
</div>
</div>
目前微调器根本没有显示或隐藏。我只在加载开始时在控制台中得到 'true',然后在加载结束时得到 'false'。 我已将加载器选择器包含在 app.component.html 文件中。它应该工作正常。我是不是做错了什么?
您应该使用 BehaviourSubject
而不是 Subject
。 Subject
仅在调用 next()
时发出值 - 如果在服务推送值后初始化组件,则不会收到任何内容。
BehaviourSubject
通过记住最后发出的值来解决这个问题。因此,当您的模板订阅时,它可以获得最后一个值并进行比较。
创建一个可以发出 HTTP 请求的布尔状态的 HttpInterceptor
非常棘手。可以同时发生多个并行请求,这并不像为每个 HttpRequest
发出 true/false 那么简单。您只需要在请求开始时发出 true 一次,而在 last 请求完成时发出 false 。
最简单的方法是跟踪并发请求数。
这是我使用的拦截器。它仅在启动新请求时发出 true,并且仅在所有请求完成时发出 false。
import {HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from '@angular/common/http';
import {Injectable} from '@angular/core';
import {Observable, Subject} from 'rxjs';
import {distinctUntilChanged, finalize, map} from 'rxjs/operators';
class BusySubject extends Subject<number> {
private _previous: number = 0;
public next(value: number) {
this._previous += value;
if (this._previous < 0) {
throw new Error('unexpected negative value');
}
return super.next(this._previous);
}
}
@Injectable()
export class BusyInterceptor implements HttpInterceptor {
private _requests: BusySubject = new BusySubject();
public get busy(): Observable<boolean> {
return this._requests.pipe(
map((requests: number) => Boolean(requests)),
distinctUntilChanged(),
);
}
public intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
this._requests.next(1);
return next.handle(req).pipe(finalize(() => this._requests.next(-1)));
}
}
p.s. This could properly be done using a scan() operator, but I haven't had time to update the code.