简体   繁体   English

如何为角度 5 中的每个 HTTP 请求显示微调器?

[英]How to Show spinner for every HTTP requests in angular 5?

i am new to angular 5 .我是 angular 5 的新手。 How to code a common function to show spinner for every HTTP request in angular 5.Please help me to implement this.如何编写一个通用函数以在 angular 5 中为每个 HTTP 请求显示微调器。请帮助我实现这一点。

You can use Angular HttpInterceptor to show a spinner for all your requests, Here's a good medium article on how to implement an http interceptor您可以使用 Angular HttpInterceptor为您的所有请求显示一个微调器,这是一篇关于如何实现 http 拦截器的优秀中篇文章

Also, you will have to create a spinner service/module and inject it in your http interceptor.此外,您必须创建一个微调服务/模块并将其注入您的 http 拦截器。 Finally, in your intercept method you can use the finally rxJs method to stop your spinner.最后,在您的拦截方法中,您可以使用finally rxJs 方法来停止您的微调器。 Here's a simple implementation:这是一个简单的实现:

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    this.spinnerService.start();
    return next.handle(req).finally(res => this.spinnerService.stop() );
}

Enjoy!享受!

Bonus: Here's a spinner service implementation example奖励:这是一个微调服务实现示例

Source Link来源链接

Create a service创建服务

//loader.service.ts
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';

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

  public isLoading = new BehaviorSubject(false);
  constructor() { }
}

Create Loader Interceptor创建加载器拦截器

    // loader.interceptors.ts
    import { Injectable } from '@angular/core';
    import {
        HttpErrorResponse,
        HttpResponse,
        HttpRequest,
        HttpHandler,
        HttpEvent,
        HttpInterceptor
    } from '@angular/common/http';
    import { Observable } from 'rxjs';
    import { LoaderService } from './loader.service';

    @Injectable()
    export class LoaderInterceptor implements HttpInterceptor {
        private requests: HttpRequest<any>[] = [];

        constructor(private loaderService: LoaderService) { }

        removeRequest(req: HttpRequest<any>) {
            const i = this.requests.indexOf(req);
            if (i >= 0) {
                this.requests.splice(i, 1);
            }
            this.loaderService.isLoading.next(this.requests.length > 0);
        }

        intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

            this.requests.push(req);
            console.log("No of requests--->" + this.requests.length);
            this.loaderService.isLoading.next(true);
            return Observable.create(observer => {
                const subscription = next.handle(req)
                    .subscribe(
                        event => {
                            if (event instanceof HttpResponse) {
                                this.removeRequest(req);
                                observer.next(event);
                            }
                        },
                        err => {
                            alert('error returned');
                            this.removeRequest(req);
                            observer.error(err);
                        },
                        () => {
                            this.removeRequest(req);
                            observer.complete();
                        });
                // remove request from queue when cancelled
                return () => {
                    this.removeRequest(req);
                    subscription.unsubscribe();
                };
            });
        }
    }

Now create a loader component then add in the app component现在创建一个加载器组件,然后添加应用程序组件

  //loader.interceptor.ts
  import { Component, OnInit } from '@angular/core';
  import { LoaderService } from '../loader.service';

  @Component({
    selector: 'app-loading',
    templateUrl: './loading.component.html',
    styleUrls: ['./loading.component.css']
  })
  export class LoaderComponent implements OnInit {

    loading: boolean;
    constructor(private loaderService: LoaderService) {
      this.loaderService.isLoading.subscribe((v) => {
        console.log(v);
        this.loading = v;
      });
    }
    ngOnInit() {
    }

  }

The complete guide is here with a material mat-progress-spinner usage.完整的指南在这里有一个材料mat-progress-spinner用法。 Very cool!很酷!

This has nothing to do with HttpClient or HTTP Requests.这与 HttpClient 或 HTTP 请求无关。 It is a question of how to handle asynchronous calls in general (HTTP or not).这是一个如何处理一般异步调用(HTTP 与否)的问题。

You should have你应该有

<div class="spinner" *ngIf="loading"; else showWhenLoaded"><div>
<ng-template #showWhenLoaded>
    <div>Your Content</div>
</ng-template>

and in the ts-file:并在 ts 文件中:

loading: boolean = true;

methodToTriggerRequest() {
    this.loading = true;
    this.http.get(...).subscribe(response => {
        if (resposnseNotAnError(response)) {this.loading = false}
    })
}

You can create a service and then publish events to it while in the root level of the application subscribed to it.您可以创建一个服务,然后在订阅它的应用程序的根级别向它发布事件。 Let me explain.让我解释。

broadcast.service.ts (this is your service) broadcast.service.ts (这是你的服务)

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

import { Subject } from 'rxjs/Subject';
import { Subscription } from 'rxjs/Subscription';

import 'rxjs/add/operator/filter'
import 'rxjs/add/operator/map'

/**
 * This class acting as event service bus for the entire app.
 * No Need to register the class as this registered in the root level.
 * Can just inject to componets.
 */
@Injectable()
export class BroadcastService {

    private _handler: Subject<Message> = new Subject<Message>();

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

    subscribe(type: string, callback: (payload: any) => void): Subscription {
        return this._handler
            .filter(message => message.type === type)
            .map(message => message.payload)
            .subscribe(callback);
    }
}

interface Message {
    type: string;
    payload: any;
}

Then in you can publish and subscribe to events like this:然后你可以发布和订阅这样的事件:

your service level:您的服务水平:

this.broadcastService.broadcast('PROGRESS_START');

In your app component level:在您的应用组件级别:

this.broadcastService.subscribe('PROGRESS_START', ()=>{
  //hit when you start http call
  this.myLoader = true;
});

finally in app.component.html:最后在 app.component.html 中:

<div *ngIf="myLoader">
 <!--YOUR LOADER SHOULD GO HERE-->
</div>
<router-outlet></router-outlet>

This is very generic loosely coupled way to implement any loader you want.这是一种非常通用的松耦合方式来实现您想要的任何加载器。

Here I have written some steps to create your own custom progressbar.在这里,我编写了一些步骤来创建您自己的自定义进度条。

  1. Create a component创建组件

    import { Component, Input } from '@angular/core';从“@angular/core”导入{组件,输入}; @Component({ selector: 'app-sw-progressbar', template: <div *ngIf="loading"> <mat-progress-bar style="position:absolute; left:15px; width: calc(100% - 30px); height:5px;" color="primary" mode="indeterminate"> </mat-progress-bar> </div> , }) export class SWProgresbarComponent { @Input() loading = false; @Component({ selector: 'app-sw-progressbar', template: <div *ngIf="loading"> <mat-progress-bar style="position:absolute; left:15px; width: calc(100% - 30px); height:5px;" color="primary" mode="indeterminate"> </mat-progress-bar> </div> , }) 导出类 SWProgresbarComponent { @Input() loading = false; constructor() { } }构造函数(){}}

2 Import component in module:- 2 在模块中导入组件:-

import { SWProgresbarComponent } from '../sw-progressbar.component';
@NgModule({
declarations: [SWProgresbarComponent],
imports: [
CommonModule,
MaterialModule,
RouterModule
],
exports: [SWProgresbarComponent,
RouterModule
]
})
export class SharedModule { }
  1. How to use it?如何使用它?

    Here loading would be true in the component where you want to show.在您要显示的组件中,这里的加载是正确的。 Add this below code in the component where you want to show the loader.在要显示加载器的组件中添加以下代码。

    <app-sw-progressbar [loading]="loading"></app-sw-progressbar>

    For spinner replace mat-progress-bar by mat-progress-spinner.对于微调器,用 mat-progress-spinner 替换 mat-progress-bar。

Create interceptor service创建拦截器服务

import { Injectable } from '@angular/core';
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Observable } from 'rxjs';
import { finalize } from 'rxjs/operators';
import { NgxSpinnerService } from 'ngx-spinner';

@Injectable()
export class SpinnerInterceptor implements HttpInterceptor {

    constructor(private spinner: NgxSpinnerService) { }

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        this.spinner.show();
        return next.handle(req).pipe(
            finalize(() => this.spinner.hide())
        );
    }
}

Provide this service in app module在应用模块中提供此服务

import { HTTP_INTERCEPTORS } from '@angular/common/http';
                 
        ....
             
@NgModule({       
    providers: [
        { provide: HTTP_INTERCEPTORS, useClass: SpinnerInterceptor, multi: true }               
    ]
})

Last in app.component inside the router-outlet add your spinner tags最后在路由器出口内的 app.component 添加您的微调器标签

 <router-outlet>
    <ngx-spinner bdColor="rgba(0,0,0,0.8)"
                 size="medium"
                 color="#fff"
                 type="timer">
        <p style="color: #fff"> Loading... </p>
    </ngx-spinner>
</router-outlet>

As you can see I am using NgxSpinner but this should make no difference if you're using custom spinner, you just need to create service to show and hide the spinner and inject this service in the spinner interceptor.正如您所看到的,我正在使用 NgxSpinner,但是如果您使用自定义微调器,这应该没有区别,您只需要创建服务来显示和隐藏微调器并将此服务注入微调器拦截器中。

In Angular's interceptor I have used "do" operator.在 Angular 的拦截器中,我使用了“do”运算符。

 intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { // handler for both success and fail response const onReqFinish = (event: HttpEvent<any>) => { if (event.type === 4) { this.onXhrFinish(); } }; this.onXhrStart(); return next.handle(req) .do( onReqFinish, onReqFinish ); }

onXhrStart function shows a loader and onXhrFinish hides it. onXhrStart 函数显示一个加载器,而 onXhrFinish 隐藏它。

Entire, working source code and demo are here完整的工作源代码和演示在这里

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM