Search code examples
angularbootstrap-4angular-httpclient

Bootstrap progress bar not auto-updating in Angular HTTP Event progress


I am trying to show the progress of my post request with HTTP Event using bootstrap progress bar. The event progress works perfectly (I am viewing it in the console) but the changes do not display in the progress bar UNLESS I click on the page. Here is my service where I am using the HTTP progress event:

progress: number = 0;
uploadClubMedia(folderName , fieldName , file): Observable<any>{
    const formData: FormData = new FormData();
    formData.append('file', file);
    return new Observable((success) => {
      const req = new HttpRequest('POST', `${constants.clubApiUrl}/media-upload/mediaFiles/${folderName}/${fieldName}`, formData, {
        reportProgress: true
      });
     this.http.request(req).subscribe((event: HttpEvent<any>) => {
        switch (event.type) {
          case HttpEventType.Sent:
            console.log('Request has been made!');
            break;
          case HttpEventType.ResponseHeader:
            console.log('Response header has been received!');
            break;
          case HttpEventType.UploadProgress:
            this.progress = Math.round(event.loaded / event.total * 100);
            // this.progress$ = new BehaviorSubject<number>(this.progress);
            console.log(`Uploaded: ${this.progress}%`);
            this.ref.tick();
            break;
          case HttpEventType.Response:
            console.log('Successfully Posted!', event.body);
            success.next(event.body);
            setTimeout(() => {
            this.progress = 0;
          }, 1500);
        }
      })
    })
}

This is my html:

<div class="progress form-group" *ngIf="mediaService.progress > 0">
  <div class="progress-bar bg-info" role="progressbar" [style.width.%]="mediaService.progress"> 
   {{mediaService.progress}}%
  </div>
</div>

I can't figure out the problem. Any help is greatly appreciated. Thank you.


Solution

  • I solved this issue using Angular's Event Emitter. The Event Emitter behaves like an RxJS Subject and it emits values once it is subscribed. So I pushed my progress value into the Event Emitter and subscribed to it inside my component. Code Below:

    (Inside Service)

    // add the eventemitter
    @Output()
      valueChanged: EventEmitter<number> = new EventEmitter<number>();
      progress: number = 0;
    
    uploadClubMedia(folderName , fieldName , file): Observable<any>{
        const formData: FormData = new FormData();
        formData.append('file', file);
        return new Observable((success) => {
          const req = new HttpRequest('POST', `${constants.clubApiUrl}/media-upload/mediaFiles/${folderName}/${fieldName}`, formData, {
            reportProgress: true
          });
         this.http.request(req).subscribe((event: HttpEvent<any>) => {
            switch (event.type) {
              case HttpEventType.Sent:
                console.log('Request has been made!');
                break;
              case HttpEventType.ResponseHeader:
                console.log('Response header has been received!');
                break;
              case HttpEventType.UploadProgress:
                this.progress = Math.round(event.loaded / event.total * 100);
                this.valueChanged.emit(this.progress);
                // this.progress$.next(this.progress);
                // this.progress$.getValue();
                console.log(`Uploaded: ${this.progress}%`);
                this.ref.tick();
                break;
              case HttpEventType.Response:
                console.log('Successfully Posted!', event.body);
                success.next(event.body);
                setTimeout(() => {
                this.progress = 0;
                this.valueChanged.emit(0);
              }, 1500);
            }
          })
        })
        //return this._clubApiService.post(`/media-upload/mediaFiles/${folderName}/${fieldName}`, formData)
      }
    
    //create a fucntion to subscribe to the value it emits
      public subscribeToProgressEvents(subscribeFn: (x: number) => any): void {
        this.valueChanged.subscribe(subscribeFn);
    }
    

    (Inside Component)

    updateProgress: number;
    
    //subscibe to the function we created inside our service
    ngOnInit() {
    this.mediaService.subscribeToProgressEvents((progress: number) => {
          this.updateProgress = progress;
          this.cf.detectChanges();
        })
    }
    

    (Inside HTML)

    <div class="progress form-group m-2" *ngIf="updateProgress > 0" style="height: 20px; 
      width:95%;">
     <div style="font-size: 16px;" class="progress-bar progress-bar-striped " 
        [ngStyle]=" 
        { 'background-color': clubPrimaryColor }" role="progressbar" 
        [style.width.%]="updateProgress">{{updateProgress}}%
      </div>
    </div>
    

    And this solves the issue.