2

我有一个组件用于加载屏幕的作用。我想在 api 调用期间显示它。

加载screen.component.html

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

加载屏幕.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 }
 ]
4

5 回答 5

1

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

于 2019-12-24T18:07:16.117 回答
0

使用单独的广播服务

广播服务 (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);
  }
}

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

订阅应用组件中的事件

显示加载组件

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

隐藏加载组件

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

在组件或服务中发布事件

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 });
            })
        );
    }

在 app.component.html 中

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

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

于 2019-12-28T22:19:34.363 回答
0

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

class LoadingService {
    runningTasks : Promise[] = [];
    addTask(promise:Promise) { 
        //push to array and set timeout
        //await success/error to remove task
    }
}
于 2019-12-27T10:07:22.707 回答
0

进行以下更改,一切顺利,

加载屏幕.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>

我在 stackOverflow 中的第一个答案。

于 2019-12-22T20:08:28.727 回答
0

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

在加载服务上添加一个 BehaviourSubject

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

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

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

希望这可以帮助

于 2019-12-24T11:11:39.620 回答