私はこのように実装されているグローバルローダーを持っています:
CoreModule:
router.events.pipe(
filter(x => x instanceof NavigationStart)
).subscribe(() => loaderService.show());
router.events.pipe(
filter(x => x instanceof NavigationEnd || x instanceof NavigationCancel || x instanceof NavigationError)
).subscribe(() => loaderService.hide());
LoaderService:
@Injectable({
providedIn: 'root'
})
export class LoaderService {
overlayRef: OverlayRef;
componentFactory: ComponentFactory<LoaderComponent>;
componentPortal: ComponentPortal<LoaderComponent>;
componentRef: ComponentRef<LoaderComponent>;
constructor(
private overlay: Overlay,
private componentFactoryResolver: ComponentFactoryResolver
) {
this.overlayRef = this.overlay.create(
{
hasBackdrop: true,
positionStrategy: this.overlay.position().global().centerHorizontally().centerVertically()
}
);
this.componentFactory = this.componentFactoryResolver.resolveComponentFactory(LoaderComponent);
this.componentPortal = new ComponentPortal(this.componentFactory.componentType);
}
show(message?: string) {
this.componentRef = this.overlayRef.attach<LoaderComponent>(this.componentPortal);
this.componentRef.instance.message = message;
}
hide() {
this.overlayRef.detach();
}
}
Angular 7.0.2で実行した場合、(私が欲しかった)動作は次のとおりです:
Angular 7.2に更新しました。現在の動作は次のとおりです。
LoaderComponent
なしでオーバーレイを表示しますNavigationStart
およびNavigationEnd
イベントにいくつかのログを追加しましたが、NavigationEnd
がNavigationStart
の直後(通常)にトリガーされ、オーバーレイが表示されないことがわかりました。約0.5秒後。
私はCHANGELOG.md
を読みましたが、この問題を説明するものは何も見つかりませんでした。どんなアイデアでも大歓迎です。
編集:
さらに調査した後、package.json
を次のように設定して、以前の動作を復元しました。
"@angular/cdk": "~7.0.0",
"@angular/material": "~7.0.0",
これの代わりに:
"@angular/cdk": "~7.2.0",
"@angular/material": "~7.2.0",
バージョン7.1.0でリリースされたコミットの誤りを確認し、関連する GitHubの問題 に問題を投稿しました。 Overlay
のフェードアウトアニメーションを修正します。
望ましい動作を実現するためのv7.1 +準拠の方法は何ですか?私によると、最善の方法は、必要な場合にのみローダーを表示することですが、NavigationStart
は必要な情報を保持していません。デバウンス動作が発生するのを避けたいのですが。
これは、delay
がUXに関して優れたソリューションであることを認識した後の結果です。これにより、ローダーは、ローダーを表示する価値があるときにのみローダーが表示できるようになりました。
counter = 0;
router.events.pipe(
filter(x => x instanceof NavigationStart),
delay(200),
).subscribe(() => {
/*
If this condition is true, then the event corresponding to the end of this NavigationStart
has not passed yet so we show the loader
*/
if (this.counter === 0) {
loaderService.show();
}
this.counter++;
});
router.events.pipe(
filter(x => x instanceof NavigationEnd || x instanceof NavigationCancel || x instanceof NavigationError)
).subscribe(() => {
this.counter--;
loaderService.hide();
});
例外リストを使用してシステムにローダーを実装する方法:
export class LoaderInterceptor implements HttpInterceptor {
requestCount = 0;
constructor(private loaderService: LoaderService) {
}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (!(REQUEST_LOADER_EXCEPTIONS.find(r => request.url.includes(r)))) {
this.loaderService.setLoading(true);
this.requestCount++;
}
return next.handle(request).pipe(
tap(res => {
if (res instanceof HttpResponse) {
if (!(REQUEST_LOADER_EXCEPTIONS.find(r => request.url.includes(r)))) {
this.requestCount--;
}
if (this.requestCount <= 0) {
this.loaderService.setLoading(false);
}
}
}),
catchError(err => {
this.loaderService.setLoading(false);
this.requestCount = 0;
throw err;
})
);
}
}
ローダーサービスは次のとおりです(300ミリ秒の遅延により、応答が速い場合にローダーが画面上で点滅するのを防ぎます)。
export class LoaderService {
loadingRequest = new BehaviorSubject(false);
private timeout: any;
setLoading(val: boolean): void {
if (!val) {
this.timeout = setTimeout(() => {
this.loadingRequest.next(val);
}, 300);
} else {
clearTimeout(this.timeout);
this.loadingRequest.next(val);
}
}
}