ngOnChanges working only when there is an action

3.4k views Asked by At

I create my own upload file component using XMLHttpRequest and everything works fine... The only issue that I have is that I create a callback method which update the progress of the upload so the user can see the percentage.

If I do a consolo.log() of the progrees, I can see how it increase from 0 to 100.

But the screen doesn't reflect that... I have this function in that component:

ngOnChanges(){
if(this.progress == 100){
  this.progress = 0;
  this.uploading = false;
}
 }

And I have a method to get the latest value of the progress (which is fired from the parent component)

public updateProgress(progress : number){
    this.progress = progress;
    console.log(this.progress);
    if(this.progress == 100)
      this.uploading = false;
  }

And if the template I have

    <div *ngIf="uploading" class="uploading">
    <progressbar [max]="100" [value]="progress"><span style="color:white; white-space:nowrap;">{{progress}} / {{100}}</span></progressbar>
</div>

So the progress bar is not increasing the progress even when in the console I can see that the value is of 'progress' changing..

But after long time, I discover that if do a click with the mouse in ANY section of the screen the ngOnChange is fired, and the progress bar is updated... So If I start doing clicks while the file is being upload I'm able to see the progress...

4

There are 4 answers

2
Günter Zöchbauer On BEST ANSWER

Inject

constructor(private cdRef:ChangeDetectorRef){}

and after you update progress, call

this.progress = ...;
this.cdRef.markForCheck();

or

this.progress = ...;
this.cdRef.detectChanges();

alternatively you can inject NgZone

constructor(private zone:NgZone){}

and do the update with

this.zone.run(() => this.progress = ...);

This causes change detection to run when Angular code is called from outside Angular in a way that Angular isn't able to recognize it.

1
Robert On

i think you missed implements OnChanges

import {Component,OnChanges, SimpleChange} from '@angular/core';
  export class yourcomponet implements OnChanges {
   ngOnChanges(changes: {[propKey: string]: SimpleChange})
    {
      // Here goes your logic
   }
}
0
Yakov Fain On

Since you haven't listed all the code, it's not clear how you parent/child components communicate. On one hand, it seems that both parent and child have the variable progress. Why?

The other question is why are you using ngOnChanges?

If your child component knows the current value of progress, create an @Output variable in the child and emit an event on each progress change.

@Output() currentProgres: EventEmitter <number> = new EventEmitter();
...
this.currentProgress.emit(progress);

In the parent, listen to these events:

<progressbar [max]="100" (currentProgress)="updateProgress($event)">
...
updateProgress(progress : number){}

The parent can have a variable showProgress bound to the UI so it'll update automatically.

0
JayDeeEss On

from the example I can see that in your child component you are inputting the property called value but in method checking progress. make sure you are putting it into a local property progress. ngOnChanges() will fire every time any input property changes. try to print console.log in your ngOnChanges() before any if() statement and check the value