Barre de progression HTTP Angular 2
Existe-t-il actuellement un moyen dans Angular 2 pour récupérer la progression (i.e. le pourcentage fait) d'un appel ajax, en utilisant le module Angular2/http?
j'utilise le code suivant pour faire mes appels 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) => {
...
});
Le but est d'écrire un système de synchronisation. Le poste sera de retour beaucoup de données, et je veux donner à l'utilisateur une indication sur la durée de la synchronisation à prendre.
4 réponses
actuellement (à partir de V. 4.3.0, en utilisant new HttpClient
@ngular/common/http
) Angular fournit l'écoute de la progression hors de la boîte. Vous avez juste besoin de créer L'objet HTTPRequest comme suit:
import { HttpRequest } from '@angular/common/http';
...
const req = new HttpRequest('POST', '/upload/file', file, {
reportProgress: true,
});
et lorsque vous vous abonnez à TO request vous obtenez l'abonnement demandé sur chaque événement progress:
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!');
}
});
Plus d'info ici.
vous pourriez tirer profit de la onprogress
événement fourni par XHR (voir ce plunkr: http://plnkr.co/edit/8MDO2GsCGiOJd2y2XbQk?p=preview).
cela permet d'obtenir des indices sur la progression du téléchargement. Ceci n'est pas supporté par Angular2 mais vous pouvez le brancher par le BrowserXhr
catégorie:
@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);
}
}
et Outrepasser le BrowserXhr
fournisseur avec l'étendue:
bootstrap(AppComponent, [
HTTP_PROVIDERS,
provide(BrowserXhr, { useClass: CustomBrowserXhr })
]);
voir cette question pour plus détails:
quand vous faites des tals http dans angular2, il renvoie une réponse Observable de type, cette réponse est créée dans la classe appelée XHRConnection où toute la magie se produit.
la XHRConnection construit la réponse en écoutant événement de charge de XMLHttpRequest, cela signifie qu'il retournera une réponse à la fin de la demande.
pour pouvoir modifier ce comportement, nous devons faire en sorte que notre classe de connexion cours événement.
nous devons donc créer une classe de connexion personnalisée, pour gérer la réponse comme bon nous semble.
je l'ai fait de cette façon, notez que mon API php renvoie plusieurs réponses dans une seule requête et que ces réponses sont des chaînes simples.
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);
}
}
Et app.composant.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})
]
.
.
.
appel à http.obtenir retournera une vapeur de réponse.
je recommande fortement l'utilisation de ce
https://www.npmjs.com/package/angular-progress-http
sinon jouer avec xhr vous fera manquer les cookies de sessions et d'autres choses
en outre, il sera plus portable et beaucoup plus facile à mettre en œuvre