Reputation: 913
I would like to pass an array of data to a child component. Depending on events in the child component the data may change:
HTML (parent):
<child-component [data]="array" (event)="updateArray()"/>
TypeScript (parent).
updateArray() {
...
this.array.push(more data)
...
}
The new data in the array should be re-rendered in the child component. But Angular does not regonize the changes.
I found a solution: https://chrislo.ca/angular-2345-change-detection-on-data-bound-array-pushunshift-popshift-or-splice/
pushAndUpdate(x) {
this.myArray = [...this.myArray, x];
}
It creates a new array.
My question is: is this the best way or is there something better?
Upvotes: 3
Views: 4790
Reputation: 57919
if you put ChangeDetectionStrategy.OnPush in children, you need use this.myArray = [...this.myArray, x];
-change the array- else you has no make any change.
the stackblitz
//hello, no change ChangeDetectionStrategy
@Component({
selector: 'hello',
template: `Hello <div *ngFor="let item of array">{{item}}</div>`,
styles: [`h1 { font-family: Lato; }`],
})
export class HelloComponent {
@Input() array: any[];
}
//hello2, ChangeDetectionStrategy
@Component({
selector: 'hello2',
template: `Hello2 <div *ngFor="let item of array">{{item}}</div>`,
styles: [`h1 { font-family: Lato; }`],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class HelloComponent2 {
@Input() array: any[];
}
main.component:
<hello [array]="array"></hello>
<hr/>
<hello2 [array]="array"></hello2>
<button (click)="click()">push</button>
<button (click)="click2()">CopyArray</button>
array=[1,2,3,4]
click2(){
this.array=[...this.array,1]
}
click(){
this.array.push(1)
}
Update there another way
In main component:
constructor(private cdr:ChangeDetectorRef){}
click3(){
this.array.push(1)
this.cdr.detectChanges()
}
Upvotes: 3
Reputation: 178
you can use subject/observables with markForCheck() in your child-component
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChildComponent implements OnInit {
@Input() data: Observable<any>;
foods: string[] = [];
constructor(private cd: ChangeDetectorRef) {}
ngOnInit() {
this.data.subscribe(food => {
this.foods = [...this.foods, ...food];
this.cd.markForCheck();
});
}
}
and in your function, you can use a subject like this
subject = new Subject();
pushAndUpdate(x) {
this.myArray.push(x);
this.myArray = this.subject.next(this.myArray);
}
for more details on the subject check out this
Upvotes: -2