2

so I'm trying to make an accurate progress bar that fills up based on the my ajax call.

This helped but I think that perhaps things have changed a little since it was written.

So I have my CustomBrowserXhr that I've added to my App Module providers to ovverride the BrowserXhr:-

@Injectable()
export class CustomBrowserXhr extends BrowserXhr {

constructor(private service: ProgressService) {}


    build(): any {
        let xhr = super.build();
        xhr.onprogress = (event) => {
            console.log(event, "event inside browser override");
            this.service.progressEventObservable.next(event);
        };
        return <any>(xhr);
    }
}

I then have a very basic progress service which other components can subscribe to:-

@Injectable()
export class ProgressService {
    progressEventObservable:Subject<any> = new Subject();
    progressEvent$ = this.progressEventObservable.asObservable();
}

I thought that I could just make http calls and I would see the console log "event inside browser override" - as it is I just get the error "EXCEPTION: browserXHR.build is not a function". Can someone shed some light one what's going wrong here please?

Thanks in advance.

Community
  • 1
  • 1
Joe Keene
  • 2,175
  • 21
  • 27

1 Answers1

2

Edit: I added the call to super(); and attached a few useful things to the event object.

Thanks for your help. This works for me. I threw both of these services into one file for brevity:

import { Injectable } from '@angular/core';
import { BrowserXhr } from '@angular/http';
import { Subject } from 'rxjs/Rx';

@Injectable()
export class ProgressService {
    progressEventObservable: Subject<any> = new Subject();
    progressEvent$ = this.progressEventObservable.asObservable();
}


@Injectable()
export class CustomBrowserXhr extends BrowserXhr {

constructor(private service: ProgressService) { super(); }

    build(): any {
        let xhr = super.build();
        let startTime = Date.now();
        xhr.upload.onprogress = (event) => {
            let timeElapsed = Date.now() - startTime;
            let uploadSpeed = event.loaded / (timeElapsed / 1000);
            let timeRemaining = Math.ceil(((event.total - event.loaded) / uploadSpeed));

            event.uploadTimeRemaining = timeRemaining;
            event.uploadSpeed = (uploadSpeed / 1024 / 1024).toFixed(2);
            event.percentCompleted = ((event.loaded / event.total) * 100).toFixed(0);
            console.log(event, "event inside browser override");
            this.service.progressEventObservable.next(event);
        };
        return <any>(xhr);
    }
}

I added the two services to my main module, just as you described:

providers: [
    ProgressService,
    { provide: BrowserXhr, useClass: CustomBrowserXhr }
],
bootstrap: [ AppComponent ]

It logged to the console as expected. Then, in the component where I upload files, I had to force change detection, but it otherwise works fine:

constructor(
private cdr: ChangeDetectorRef,
private service: ProgressService
) { 
    this.service.progressEvent$.subscribe(event => {
        this.progress = event.percentCompleted;
        this.speed = event.uploadSpeed;
        this.timeRemaining = event.uploadTimeRemaining;
        this.cdr.detectChanges();
    });
}

I tried to get it to work with async pipe, but it was only updating on the last event. What do you think?

wolfhoundjesse
  • 1,085
  • 9
  • 32
  • Looks good to me buddy, think you need a `super();` call in the CustomBrowserXhr contructor but other than that - it now works for me. I changed `xhr.upload.onprogress` to `xhr.onprogress` because I want the progress of all xhr calls. – Joe Keene Mar 20 '17 at 09:56
  • The IDE does ask for a super(); call. This works with or without. I haven't checked to see what the penalty for calling or not calling it is, but I plan to do that this week. – wolfhoundjesse Mar 20 '17 at 13:19
  • 1
    Yeah you don't have to it's just good practice and causes no harm in this particular use case. – Joe Keene Mar 20 '17 at 15:21
  • can you please create a plunkr? – Apoorv Oct 27 '17 at 09:03