I have tried this a bunch of ways. This method is very much by the book, however, my HTTP Interceptor is not forwarding the reportProgress events to my component. I can see the events at the Interceptor, but they are not at the component no matter what I try (eg {observe: 'events'}
etc). I can't figure how to get the progress in the component.
interceptor.ts
import {Component, Input, OnInit} from '@angular/core';
import {
HttpClient,
HttpRequest,
} from '@angular/common/http';
import {tap} from 'rxjs/operators';
import {AlertService} from '../../services/alert.service';
@Component({
selector: 'app-upload',
templateUrl: './upload.component.html',
styleUrls: ['./upload.component.scss']
})
export class UploadComponent implements OnInit {
constructor(private http: HttpClient, public alertService: AlertService) {
}
ngOnInit(): void {
}
files: File[] = [];
upload(files: File[]) {
this.files = files;
for (let file of files) {
const formData: FormData = new FormData();
formData.append('file', file, file.name);
const url = 'http://localhost:4000/upload';
const req = new HttpRequest('POST', url, formData, {
reportProgress: true
});
this.http.request(req)
.pipe(
tap(console.log) // ONLY THE FINAL RESPONSE HERE
)
.subscribe();
}
}
}
component.ts
import {Injectable} from '@angular/core';
import {
HttpResponse,
HttpRequest,
HttpHandler,
HttpEvent,
HttpInterceptor
} from '@angular/common/http';
import {Observable} from 'rxjs';
import {StateService} from '../services/state.service';
@Injectable()
export class LoaderInterceptor implements HttpInterceptor {
private requests: HttpRequest<any>[] = [];
constructor(private alertService: AlertService, private stateService: StateService) {
}
removeRequest(req: HttpRequest<any>) {
const i = this.requests.indexOf(req);
if (i >= 0) {
this.requests.splice(i, 1);
}
this.stateService.isLoading$.next(this.requests.length > 0);
}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
this.requests.push(req);
this.stateService.isLoading$.next(true);
return new Observable(observer => {
const subscription = next.handle(req)
.subscribe(
event => {
console.log(event); // I CAN SEE THE LOADED EVENT HERE
if (event instanceof HttpResponse) {
this.removeRequest(req);
observer.next(event);
}
},
err => {
this.alertService.setAlert('error', err.message);
this.removeRequest(req);
observer.error(err);
},
() => {
this.removeRequest(req);
observer.complete();
});
// remove request from queue when cancelled
return () => {
this.removeRequest(req);
subscription.unsubscribe();
};
});
}
}
You're only emitting the response event from the interceptor.
if (event instanceof HttpResponse) {
this.removeRequest(req);
observer.next(event);
}
You should move observer.next
out of the if block:
const subscription = next.handle(req)
.subscribe(event => {
console.log(event); // I CAN SEE THE LOADED EVENT HERE
if (event instanceof HttpResponse) {
this.removeRequest(req);
}
// MOVED HERE
observer.next(event);
}, err => {
this.alertService.setAlert('error', err.message);
this.removeRequest(req);
observer.error(err);
}, () => {
this.removeRequest(req);
observer.complete();
});
I would personally do this in a pipe rather than creating a new subscription, but that's irrelevant to the solution.