angular/aio/content/examples/http/src/app/uploader/uploader.service.ts
2018-03-19 21:51:51 -07:00

106 lines
3.3 KiB
TypeScript

import { Injectable } from '@angular/core';
import {
HttpClient, HttpEvent, HttpEventType, HttpProgressEvent,
HttpRequest, HttpResponse, HttpErrorResponse
} from '@angular/common/http';
import { of } from 'rxjs';
import { catchError, last, map, tap } from 'rxjs/operators';
import { MessageService } from '../message.service';
@Injectable()
export class UploaderService {
constructor(
private http: HttpClient,
private messenger: MessageService) {}
// If uploading multiple files, change to:
// upload(files: FileList) {
// const formData = new FormData();
// files.forEach(f => formData.append(f.name, f));
// new HttpRequest('POST', '/upload/file', formData, {reportProgress: true});
// ...
// }
upload(file: File) {
if (!file) { return; }
// COULD HAVE WRITTEN:
// return this.http.post('/upload/file', file, {
// reportProgress: true,
// observe: 'events'
// }).pipe(
// Create the request object that POSTs the file to an upload endpoint.
// The `reportProgress` option tells HttpClient to listen and return
// XHR progress events.
// #docregion upload-request
const req = new HttpRequest('POST', '/upload/file', file, {
reportProgress: true
});
// #enddocregion upload-request
// #docregion upload-body
// The `HttpClient.request` API produces a raw event stream
// which includes start (sent), progress, and response events.
return this.http.request(req).pipe(
map(event => this.getEventMessage(event, file)),
tap(message => this.showProgress(message)),
last(), // return last (completed) message to caller
catchError(this.handleError(file))
);
// #enddocregion upload-body
}
// #docregion getEventMessage
/** Return distinct message for sent, upload progress, & response events */
private getEventMessage(event: HttpEvent<any>, file: File) {
switch (event.type) {
case HttpEventType.Sent:
return `Uploading file "${file.name}" of size ${file.size}.`;
case HttpEventType.UploadProgress:
// Compute and show the % done:
const percentDone = Math.round(100 * event.loaded / event.total);
return `File "${file.name}" is ${percentDone}% uploaded.`;
case HttpEventType.Response:
return `File "${file.name}" was completely uploaded!`;
default:
return `File "${file.name}" surprising upload event: ${event.type}.`;
}
}
// #enddocregion getEventMessage
/**
* Returns a function that handles Http upload failures.
* @param file - File object for file being uploaded
*
* When no `UploadInterceptor` and no server,
* you'll end up here in the error handler.
*/
private handleError(file: File) {
const userMessage = `${file.name} upload failed.`;
return (error: HttpErrorResponse) => {
// TODO: send the error to remote logging infrastructure
console.error(error); // log to console instead
const message = (error.error instanceof Error) ?
error.error.message :
`server returned code ${error.status} with body "${error.error}"`;
this.messenger.add(`${userMessage} ${message}`);
// Let app keep running but indicate failure.
return of(userMessage);
};
}
private showProgress(message: string) {
this.messenger.add(message);
}
}