I have a component 'bar' inside ngFor. I want to update its width with animation starting from the previous value to new one.
html :
<div *ngFor="let station of stations" class="station">
<bar [perc]="station.perc" class="bar"></bar>
</div>
ParentComponent :
ngOnInit(){
setInterval(() => this.updateData(), 10000);
}
updateData(){
const url = 'http://....';
this.http.get(url)
.map(res => res.json())
.subscribe(data => {
this.stations = data;
});
}
BarComponent
export class BarComponent {
@Input() perc;
constructor(private element: ElementRef){}
ngOnChanges(changes: any): void {
let perc = changes.perc.currentValue;
TweenMax.to(this.element.nativeElement, 1, { width: perc + '%' });
}
}
But on each updateData() it looks like ngFor recreates the dom and BarComponent is constructed again. So even if 'station.perc' is the same, ngOnChanges() is fired.
And the transition keeps on restarting from 0 instead of starting from the previous value...
I probably miss a crucial point here but whats the clean workaround?
Angular provides a method called trackBy , which is used to track our incoming data every time we get a request from an API. Suppose we have some data coming from an API request into the collection, and we need to change the data over the web page using the ngFor directive.
While you are not allowed to use *ngIf and *ngFor in the same div (it will gives an error in the runtime) you can nest the *ngIf in the *ngFor to get the desired behavior.
NgFor is a structural directive, meaning that it changes the structure of the DOM . It's point is to repeat a given HTML template once for each value in an array, each time passing it the array value as context for string interpolation or binding.
*ngFor is a predefined directive in Angular. It accepts an array to iterate data over atemplate to replicate the template with different data. It's the same as the forEach() method in JavaScript, which also iterates over an array.
I guess you should use trackBy
option to customize the default tracking algorithm the ngFor
directive:
view
<div *ngFor="let station of stations; let i = index; trackBy: trackByFn" class="station">
<bar [perc]="station.perc" class="bar"></bar>
</div>
component
trackByFn(index, item) {
return index;
}
or a bit better use unique id:
trackByFn(index, station) {
return station.id;
}
See more details about the trackBy here:
Hope Plunker Example will also help you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With