Angular2:显示每个HTTP请求的活动指示器并隐藏视图直到完成

Car*_*ras 15 http angular

我是Angular2的新手,我想知道是否有任何方法可以显示每个HTTP请求的活动指示器并隐藏视图直到完成?

d18*_*820 17

一种方法是为Angular2 Http编写一个拦截器.通过创建自己的http实例,您可以在使用"提供"方法引导应用程序时将其交换.完成此操作后,可以创建一个PubSub服务,以便从Http拦截器发布和订阅这些事件,并在每个请求发出事件之前和之后发出.

Plunker上可以看到一个实例

拦截器:

import {Injectable} from 'angular2/core';
import {HTTP_PROVIDERS, Http, Request, RequestOptionsArgs, Response, XHRBackend, RequestOptions, ConnectionBackend, Headers} from 'angular2/http';
import 'rxjs/Rx';
import {PubSubService} from './pubsubService';

@Injectable()
export class CustomHttp extends Http {
  _pubsub: PubSubService
   constructor(backend: ConnectionBackend, defaultOptions: RequestOptions, pubsub: PubSubService) {
        super(backend, defaultOptions);
        this._pubsub = pubsub;
    }

    request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
        return this.intercept(super.request(url, options));
    }

    get(url: string, options?: RequestOptionsArgs): Observable<Response> {
        return this.intercept(super.get(url,options));
    }

    post(url: string, body: string, options?: RequestOptionsArgs): Observable<Response> {   
        return this.intercept(super.post(url, body, this.getRequestOptionArgs(options)));
    }

    put(url: string, body: string, options?: RequestOptionsArgs): Observable<Response> {
        return this.intercept(super.put(url, body, this.getRequestOptionArgs(options)));
    }

    delete(url: string, options?: RequestOptionsArgs): Observable<Response> {
        return this.intercept(super.delete(url, options));
    }

    getRequestOptionArgs(options?: RequestOptionsArgs) : RequestOptionsArgs {
        if (options == null) {
            options = new RequestOptions();
        }
        if (options.headers == null) {
            options.headers = new Headers();
        }
        options.headers.append('Content-Type', 'application/json');
        return options;
    }

    intercept(observable: Observable<Response>): Observable<Response> {
      this._pubsub.beforeRequest.emit("beforeRequestEvent");
      //this will force the call to be made immediately..  
      observable.subscribe(
            null,
            null,
            () => this._pubsub.afterRequest.emit("afterRequestEvent");
          );  
      return observable
    }


}
Run Code Online (Sandbox Code Playgroud)

发射器

import {Subject } from 'rxjs/Subject';

export class RequestEventEmitter extends Subject<String>{
    constructor() {
        super();
    }
    emit(value) { super.next(value); }
}

export class ResponseEventEmitter extends Subject<String>{
    constructor() {
        super();
    }
    emit(value) { super.next(value); }
}
Run Code Online (Sandbox Code Playgroud)

PubSubService

import {Injectable} from 'angular2/core';
import {RequestEventEmitter, ResponseEventEmitter} from './emitter';

@Injectable()
export class PubSubService{
   beforeRequest:RequestEventEmitter;
   afterRequest:ResponseEventEmitter;
   constructor(){
       this.beforeRequest = new RequestEventEmitter();
       this.afterRequest = new ResponseEventEmitter();
   }
}
Run Code Online (Sandbox Code Playgroud)

引导应用程序

//main entry point
import {bootstrap} from 'angular2/platform/browser';
import {provide} from 'angular2/core';
import {Http, HTTP_PROVIDERS, XHRBackend, RequestOptions} from 'angular2/http';
import {HelloWorldComponent} from './hello_world';
import {CustomHttp} from './customhttp';
import {PubSubService} from './pubsubService'

bootstrap(HelloWorldComponent, [HTTP_PROVIDERS,PubSubService, 
    provide(Http, {
        useFactory: (backend: XHRBackend, defaultOptions: RequestOptions, pubsub: PubSubService) 
           => new CustomHttp(backend, defaultOptions, pubsub),
        deps: [XHRBackend, RequestOptions, PubSubService]
    })
]).catch(err => console.error(err));
Run Code Online (Sandbox Code Playgroud)

现在在您的加载组件中,它就像订阅事件和设置要显示的属性一样简单

export class LoaderComponent implements OnInit {
    showLoader = false;
  _pubsub:PubSubService;

  constructor(pubsub: PubSubService) {
    this._pubsub = pubsub;
  }
   ngOnInit() {
     this._pubsub.beforeRequest.subscribe(data => this.showLoader = true);
     this._pubsub.afterRequest.subscribe(data => this.showLoader = false);   
  }
}
Run Code Online (Sandbox Code Playgroud)

虽然最终会有更多代码,但如果您希望在应用程序中的每个请求上收到通知,那么就可以执行此操作.拦截器需要注意的一件事是,因为正在为每个请求立即执行所有请求的订阅,这可能不是您在特定情况下所需要的.解决方案是支持常规的Angular2 Http并使用CustomHttp作为第二个选项,可以在需要时注入.我认为在大多数情况下,立即订阅可以正常工作.我很想听听它不会的例子.

  • 问题是Http lib已经改变,并且所有原型方法(get,post,put,delete)都在现在向基本Request方法发出请求,并覆盖了相应的选项.要解决此问题,只需注释掉或从CustomHttp模块中删除Post,Put,Delete,Get方法.[Plunker](https://embed.plnkr.co/A3rL1l).拦截只需要在基本Request原型方法中完成. (3认同)
  • 我认为你可以使用.do而不是在拦截中订阅 - [Plunker](http://plnkr.co/edit/OOxfpPP2HUn4Ujy7UrZx?p=preview).`intercept(observable:Observable <Response>):Observable <Response> {this._pubsub.beforeRequest.emit("beforeRequestEvent"); return observable.do(()=> this._pubsub.afterRequest.emit("afterRequestEvent")); }` (2认同)

tib*_*bus 16

是的,您需要为每个视图处理:

  • 您可以为http请求提供服务,该服务将返回Observable
  • 在组件中,您将具有加载状态
  • 在从服务器请求数据之前,需要将加载状态设置为true,然后在完成数据提取时将其设置为false.
  • 在模板中使用ngIf隐藏/显示加载或内容

    Ex:

服务 :

@Injectable()
export class DataService {
    constructor(private http: Http) { }

    getData() {
       return this.http.get('http://jsonplaceholder.typicode.com/posts/2');
    }
} 
Run Code Online (Sandbox Code Playgroud)

组件:

@Component({
  selector: 'my-app',
  template : `
    <div *ngIf="loading == true" class="loader">Loading..</div>
    <div *ngIf="loading == false">Content.... a lot of content <br> more content</div>`
}) 
export class App {
  loading: boolean; 

  constructor(private dataService: DataService) {  }

  ngOnInit() {
    // Start loading Data from the Server
    this.loading = true;

    this.dataService.getData().delay(1500).subscribe( 
      requestData => { 
        // Data loading is Done
        this.loading = false;

        console.log('AppComponent', requestData);
      } 
  } 
}
Run Code Online (Sandbox Code Playgroud)

可以在这里找到一个工作示例:http://plnkr.co/edit/HDEDDLOeiHEDd7VQaev5?p = preview