2016-05-11 25 views
14

Czy istnieje obecnie sposób wewnątrz Angular 2, aby pobrać postęp (tj. Procent wykonania) wywołania ajax, używając modułu angular2/http?Kątowy 2 pasek postępu HTTP

używam następujący kod, aby moje rozmowy http:

 let body = JSON.stringify(params); 
     let headers = new Headers({ 'Content-Type': 'application/json' }); 
     let options = new RequestOptions({ headers: headers }); 
     this.http.post(url, body, options) 
      .timeout(10000, new Error('Timeout exceeded during login')) 
      .toPromise() 
      .then((res) => { 
       ... 
      }).catch((err) => { 
       ... 
      }); 

Celem jest, aby napisać system synchronizacji. Post zwróci wiele danych i chcę dać użytkownikowi wskazówkę, jak długo potrwa synchronizacja.

Odpowiedz

6

Można wykorzystać wydarzenie onprogress dostarczone przez XHR (patrz: ten plunkr: http://plnkr.co/edit/8MDO2GsCGiOJd2y2XbQk?p=preview).

Pozwala to uzyskać wskazówki dotyczące postępów pobierania. To nie jest obsługiwany po wyjęciu z pudełka przez Angular2 ale można go podłączyć przez rozszerzonego klasy BrowserXhr:

@Injectable() 
export class CustomBrowserXhr extends BrowserXhr { 
    constructor(private service:ProgressService) {} 
    build(): any { 
    let xhr = super.build(); 
    xhr.onprogress = (event) => { 
     service.progressEventObservable.next(event); 
    }; 
    return <any>(xhr); 
    } 
} 

i zastąpić dostawcę BrowserXhr z rozszerzonym:

bootstrap(AppComponent, [ 
    HTTP_PROVIDERS, 
    provide(BrowserXhr, { useClass: CustomBrowserXhr }) 
]); 

zobaczyć to pytanie więcej szczegóły:

+0

Miałem nadzieję, że unikam wykonawcze w XHRRequest :) ale nic z tym zrobić;) –

+0

W rzeczywistości, to nie jest obsługiwana (jeszcze) w podporze HTTP Angular2 więc trzeba wyraźnie powołać się na XHR ... –

3

Gdy robisz http cals w kanale 2, zwraca on Observable of Response, ta odpowiedź jest tworzona w klasie o nazwie XHRConnection, gdzie dzieje się cała magia.

Połączenie XHRConnection buduje odpowiedź, nasłuchując zdarzenia XMLHttpRequest obciążenia, oznacza to, że zwróci jedną odpowiedź na końcu żądania.

Teraz, aby móc zmienić to zachowanie, czego potrzebujemy, aby nasza klasa połączenie słuchać postępu imprezy.

Musimy więc utworzyć niestandardową klasę połączenia, aby obsłużyć odpowiedź zgodnie z naszym wyobrażeniem.

Zrobiłem to w ten sposób, Zauważ, że mój API PHP zwraca wiele odpowiedzi w jednym żądaniu, a te odpowiedzi są zwykłymi ciągami.

my_backend.ts

import {Injectable} from "angular2/core"; 
import {Observable} from "rxjs/Observable"; 
import {Observer} from "rxjs/Observer"; 
import {Connection,ConnectionBackend} from "angular2/src/http/interfaces"; 
import {ReadyState, RequestMethod, ResponseType} from "angular2/src/http/enums"; 
import {ResponseOptions} from "angular2/src/http/base_response_options"; 
import {Request} from "angular2/src/http/static_request"; 
import {Response} from "angular2/src/http/static_response"; 
import {BrowserXhr} from "angular2/src/http/backends/browser_xhr"; 
import {Headers} from 'angular2/src/http/headers'; 
import {isPresent} from 'angular2/src/facade/lang'; 
import {getResponseURL, isSuccess} from "angular2/src/http/http_utils" 

export class MyConnection implements Connection { 
    readyState: ReadyState; 
    request: Request; 
    response: Observable<Response>; 

    constructor(req: Request, browserXHR: BrowserXhr, baseResponseOptions?: ResponseOptions) {  
     this.request = req; 
     this.response = new Observable<Response>((responseObserver: Observer<Response>) => { 
      let _xhr: XMLHttpRequest = browserXHR.build(); 
      _xhr.open(RequestMethod[req.method].toUpperCase(), req.url); 
      // save the responses in array 
      var buffer :string[] = []; 
      // load event handler 
      let onLoad =() => { 
       let body = isPresent(_xhr.response) ? _xhr.response : _xhr.responseText; 
       //_xhr.respons 1 = "Loading data!" 
       //_xhr.respons 2 = "Loading data!Ready To Receive Orders." 
       // we need to fix this proble 
       // check if the current response text contains the previous then subtract 
       // NOTE: I think there is better approach to solve this problem. 
       buffer.push(body); 
       if(buffer.length>1){ 
        body = buffer[buffer.length-1].replace(buffer[buffer.length-2],''); 
       } 
       let headers = Headers.fromResponseHeaderString(_xhr.getAllResponseHeaders()); 
       let url = getResponseURL(_xhr); 
       let status: number = _xhr.status === 1223 ? 204 : _xhr.status; 
       let state:number = _xhr.readyState; 
       if (status === 0) { 
        status = body ? 200 : 0; 
       } 
       var responseOptions = new ResponseOptions({ body, status, headers, url }); 
       if (isPresent(baseResponseOptions)) { 
        responseOptions = baseResponseOptions.merge(responseOptions); 
       } 
       let response = new Response(responseOptions); 
       //check for the state if not 4 then don't complete the observer 
       if(state !== 4){ 
        //this will return stream of responses 
        responseObserver.next(response); 
        return; 
       } 
       else{ 
        responseObserver.complete(); 
        return; 
       } 
       responseObserver.error(response); 
      }; 
      // error event handler 
      let onError = (err: any) => { 
       var responseOptions = new ResponseOptions({ body: err, type: ResponseType.Error }); 
       if (isPresent(baseResponseOptions)) { 
        responseOptions = baseResponseOptions.merge(responseOptions); 
       } 
       responseObserver.error(new Response(responseOptions)); 
      }; 

      if (isPresent(req.headers)) { 
       req.headers.forEach((values, name) => _xhr.setRequestHeader(name, values.join(','))); 
      } 
      _xhr.addEventListener('progress', onLoad); 
      _xhr.addEventListener('load', onLoad); 
      _xhr.addEventListener('error', onError); 

      _xhr.send(this.request.text()); 

      return() => { 
       _xhr.removeEventListener('progress', onLoad); 
       _xhr.removeEventListener('load', onLoad); 
       _xhr.removeEventListener('error', onError); 
       _xhr.abort(); 
      }; 
     }); 
    } 
} 
@Injectable() 
export class MyBackend implements ConnectionBackend { 
    constructor(private _browserXHR: BrowserXhr, private _baseResponseOptions: ResponseOptions) {} 
    createConnection(request: Request):MyConnection { 
    return new MyConnection(request, this._browserXHR, this._baseResponseOptions); 
    } 
} 

A w app.component.ts

import {Component, provide} from 'angular2/core'; 
import {HTTP_PROVIDERS,XHRBackend} from 'angular2/http'; 
import {MyBackend} from './my_backend'; 
@Component({ 
    selector: 'my-app', 
    providers: [ 
     HTTP_PROVIDERS, 
     MyBackend, 
     provide(XHRBackend, {useExisting:MyBackend}) 
    ] 
    . 
    . 
    . 

Teraz nazywając http.get zwróci parę odpowiedzi.

1

Gorąco polecam za pomocą tego

https://www.npmjs.com/package/angular-progress-http

inaczej bawić z XHR będzie można przegapić sesje cookie i innych spożywczych

oprócz to będzie bardziej mobilny i sposób łatwiejsze do wdrożenia

+0

Działa to świetnie, dopóki nie zostanie uaktualniony do Angular 5, a następnie pakiet nie powiedzie się, ponieważ odwołuje się do OpaqueToken. –

+1

Wolałbym nauczyć się techniki, zamiast kopiować czyjeś kody – Ronit

9

Obecnie (od wersji 4.3.0, gdy używany jest nowy HttpClient z @ngular/common/http) Angular zapewnia słuchanie postępu po wyjęciu z pudełka. Trzeba tylko stworzyć HTTPRequest obiektu jak poniżej:

import { HttpRequest } from '@angular/common/http'; 
... 

const req = new HttpRequest('POST', '/upload/file', file, { 
    reportProgress: true, 
}); 

A kiedy zapisać się do żądania dostaniesz subskrypcji nazwie na każdą imprezę toku:

http.request(req).subscribe(event => { 
    // Via this API, you get access to the raw event stream. 
    // Look for upload progress events. 
    if (event.type === HttpEventType.UploadProgress) { 
    // This is an upload progress event. Compute and show the % done: 
    const percentDone = Math.round(100 * event.loaded/event.total); 
    console.log(`File is ${percentDone}% uploaded.`); 
    } else if (event instanceof HttpResponse) { 
    console.log('File is completely uploaded!'); 
    } 
}); 

Więcej informacji here.