2016-05-27 28 views

回答

16

是的,你需要處理的是每個視圖:

  • 您可以對HTTP請求的服務,這將返回一個 可觀察
  • 在組件,你將有一個加載狀態
  • 在您請求來自 服務器的數據之前,您需要將加載狀態設置爲true,然後在數據提取完成時將其設置爲false。
  • 在模板中使用ngIf隱藏/顯示加載或內容

    例:

的服務:

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

    getData() { 
     return this.http.get('http://jsonplaceholder.typicode.com/posts/2'); 
    } 
} 

組件:

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

可以在這裏找到一個工作示例:http://plnkr.co/edit/HDEDDLOeiHEDd7VQaev5?p=preview

+0

簡單而簡單。大。 ty – angryip

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 
    } 


} 

發射器

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

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

自舉應用

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

現在,在您加載組件的那麼容易,因爲訂閱的事件和設置屬性來顯示或不

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

雖然這結束了多一點代碼,如果您希望在應用程序中收到每個請求的通知,這就可以做到。關於攔截器的一件事情是,因爲每次請求都會立即執行訂閱,所有請求都將被執行,這可能不是您在特定情況下需要的。解決方案是支持常規的Angular2 Http,並使用CustomHttp作爲第二個選項,可以在需要時注入。我認爲在大多數情況下立即訂閱可以正常工作。我很樂意聽到它不會的例子。

+2

我想你可以使用.do而不是訂閱截取 - [Plunker](http://plnkr.co/edit/OOxfpPP2HUn4Ujy7UrZx?p=preview)。 (可觀察到:Observable ):Observable {this._pubsub.beforeRequest.emit(「beforeRequestEvent」); return observable.do(()=> this._pubsub.afterRequest.emit(「afterRequestEvent」)); }' –

+1

使用'do()'應該是正確的答案,因爲@BrianChance建議您在訂閱它們時進行兩次請求,因爲它們是冷的可觀察對象。運行plunk時查看網絡選項卡。 – Yodacheese

+0

由@ b1820描述的實現,由@BrianChance建議的'do()'在Angular v2.0.1中使用時非常有魅力,但是自從升級到v2.2.0以來,它有點小問題。 Ceteris paribus,回調現在被稱爲兩次(onSuccess和onError)。我搜查了一下,但找不到有什麼問題;我也找不到一個2.2.0的CDN來製作一個plunkr,但它應該很容易在本地項目上重現。有誰知道什麼可能是錯誤的? – phl

2

添加一個像這樣的通用DAL(數據訪問層)類,並在您的組件中使用此DAL類。

將加載指示器添加爲服務或組件,並使用您的自定義樣式。

export class DAL { 
    private baseUrl: string = environment.apiBaseUrl; 

    private getConsolidatedPath(path: string) { 
     if (path.charAt(0) === '/') { 
      path = path.substr(1); 
     } 
     return `${this.baseUrl}/${path}`; 
    } 

    private callStack = []; 

    private startCall() { 
     this.loadingIndicator.display(true); 
     this.callStack.push(1); 
    } 

    private endCall() { 
     this.callStack.pop(); 
     if (this.callStack.length === 0) { 
      this.loadingIndicator.display(false); 
     } 
    } 


    public get(path: string) { 
     this.startCall(); 
     return this.http.get(this.getConsolidatedPath(path), { headers: this.getHeaders() }) 
      .map(response => response.json()) 
      .catch(e => this.handleError(e)) 
      .finally(() => this.endCall()); 
    } 
    public put(path: string, data: any) { 
     this.startCall(); 
     return this.http.put(this.getConsolidatedPath(path), data, { headers: this.getHeaders() }) 
      .map(response => response.json()) 
      .catch(e => this.handleError(e)) 
      .finally(() => this.endCall()); 

    } 

    public post(path: string, data: any) { 
     this.startCall(); 
     return this.http.post(this.getConsolidatedPath(path), data, { headers: this.getHeaders() }) 
      .map(response => response.json()) 
      .catch(e => this.handleError(e)) 
      .finally(() => this.endCall()); 
    } 
    public delete(path: string, data: any) { 
     this.startCall(); 
     return this.http.delete(this.getConsolidatedPath(path), { body: data, headers: this.getHeaders() }) 
      .map(response => response.json()) 
      .catch(e => this.handleError(e)) 
      .finally(() => this.endCall()); 
    } 

    constructor(public http: Http, public loadingIndicator: LoadingIndicatorService) { 
    } 

} 
1

此外@tibbus響應

這是更好地設置「isLoading」 Number類型,並保持它的服務。

與布爾:

請求1點開始 - >上微調 - >請求2開始 - >請求1周的端部 - >微調器關閉 - >請求2結束

與數:

請求1開始 - >旋塗器上 - >請求2開始 - >請求1周的端部 - >請求2周的端部 - >旋轉器關閉

服務

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

    private set fetchCounter(v:number) { 
     this._fetchCounter = v; 
     this.isLoadingSource.next(this._fetchCounter > 0) 
    } 
    private get fetchCounter() { return this._fetchCounter }; 
    private _fetchCounter:number = 0; 

    private isLoadingSource = new Subject<boolean>(); 
    public isLoading = this.isLoadingSource.asObservable(); 

    public getData() { 
     this.fetchCounter++; 
     return this.http.get('http://jsonplaceholder.typicode.com/posts/2') 
      .map(r => { 
       this.fetchCounter--; 
       return r; 
      }); 
    } 
} 

您只需訂閱來自任何組件的isLoading。

相關問題