在 api 调用时显示组件

Displaying a component upon an api call

我有一个用于加载屏幕的组件。我想在 api 通话期间展示它。

正在加载-screen.component.html

<div *ngIf="isLoading | async" class="overlay">
 //Some html for the loading screen.
</div>

正在加载-screen.component.ts

isLoading: Subject<boolean> = this.loaderService.isLoading;

顺便说一下,当我将 isLoading 设置为真正的硬编码时,组件淡入并且我看到了我应该看到的加载屏幕。所以我假设这个组件没有任何问题。

正在加载-screen.interceptor.ts

@Injectable()
export class LoaderInterceptor implements HttpInterceptor {
  constructor(public loaderService: LoadingScreenService) { }
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    this.loaderService.show();
    return next.handle(req).pipe(
        finalize(() => this.loaderService.hide())
    );
  }
}

我没有共享 api 调用,但它不是必需的,因为我看到在调试时进行 api 调用时触发了 show() 和 hide() 方法。

正在加载-screen.service.ts

 @Injectable({
  providedIn: 'root'
 })
 export class LoadingScreenService {

 isLoading = new Subject<boolean>();

 constructor() { }

 show() {
  this.isLoading.next(true);
 }

 hide() {
  this.isLoading.next(false);
 }
}

app.module.ts

providers: [
   LoadingScreenService,
   { provide: HTTP_INTERCEPTORS, useClass: LoaderInterceptor, multi: true }
 ]

进行以下更改,您就可以开始了,

加载中-screen.component.ts

loadingFlag : boolean;

constructor(private loaderService:loaderService){
this.loaderService.subscribe(value => (this.loadingFlag = value));
}

正在加载-screen.component.html

<div *ngIf="loadingFlag" class="overlay">
//Some html for the loading screen.
</div>

My First Answer in Whosebug.

试试看 在 LoadingScreenService 上将其类型从 Subject 更改为 BehaviourSubject 类型并从登录组件订阅它

在加载服务上添加一个 BehaviourSubject

isLoading:BehaviourSubject = new BehaviourSubject<boolean>();

在组件构造器或ngOnInit中添加订阅

this.loadingService.isLoading.subscribe(res=>{
 this.isLoading = res;
});

希望对您有所帮助

我发现了问题。似乎我在 app.component.ts 中留下了提供者描述,它搞砸了一切,甚至没有给出错误。我的错。

将加载作为布尔值处理过于简单化了问题。我认为更好的方法是使用 Promise 数组并检查它的长度,其中每个 promise 代表正在加载的异步任务,因此只有在任务数组为空或任务超时时才删除加载指示器(或任何其他 completion/cancelation 逻辑)。

class LoadingService {
    runningTasks : Promise[] = [];
    addTask(promise:Promise) { 
        //push to array and set timeout
        //await success/error to remove task
    }
}

使用单独的广播服务

BroadcastService (broadcast.service.ts)

import { Injectable } from '@angular/core';

import { Subject, Subscription } from 'rxjs';
import { filter, map } from 'rxjs/operators';

@Injectable()
export class BroadcastService {
  private handler: Subject<any> = new Subject<any>();

  broadcast(type: string, action: any = null) {
    this.handler.next({ type, action });
  }

  subscribe(type: string, callback: (action: any) => void): Subscription {
    return this.handler
      .pipe(
        filter(info => info.type === type),
        map(info => info.action)
      )
      .subscribe(callback);
  }
}

此 class 充当整个应用程序的事件服务总线。 Class 不需要注册,因为它是在根级别注册的。可以注入组件。

Subscribe to events in app component

显示加载组件

this.broadcastService.subscribe('SHOW_lOADING_COMPONENT', ()=>{
  this.isLoading= true;
});

隐藏加载组件

this.broadcastService.subscribe('HIDE_lOADING_COMPONENT', ()=>{
  this.isLoading= true;
});

Publish events inside components or services

get<T>(path: string, params: HttpParams): Observable<T> {

        this.broadcastService.broadcast('SHOW_lOADING_COMPONENT', null);

        return this.httpClient
            .get<T>(path, { headers: this.setHeaders(), params })
            .pipe(catchError(err => {

        this.broadcastService.broadcast('HIDE_lOADING_COMPONENT', null);

        this.handleError(err);
        return of<any>({ isSuccess: false, error: err });
            })
        );
    }

In app.component.html

<div *ngIf="isLoading | async" class="overlay">
 //Some html for the loading screen.
</div>
<router-outlet></router-outlet>

注意 :通过这种方式,您可以发布和订阅越来越多的事件,这些事件以可重用性和松散耦合的方式指导应用程序。