Reputation: 545
I have a Parent Component with an array of Objects.
I use an *ngFor loop to populate Child Components via an @Input() with the element at each index.
If I change the object at an index, the child component completely resets instead of just accepting the new Input and maintaining it's other properties.
export interface MyObject {
a: string;
b: string;
}
export class Parent {
objectArray: MyObject[] = [
{a: 'string A', b: 'string B'}
];
changeAnObject() {
const sameObject: MyObject = {a: 'string A', b: 'string B'};
this.objectArray[0] = sameObject;
}
}
export class Child {
@Input() inputObject: MyObject;
selected = false; // Some other property to maintain
}
// 3 different ways to populate inputObject
<div *ngFor="let object of objectArray">
<app-child [inputObject]="object"></app-child> // does not maintain "selected" property
</div>
<div *ngFor="let object of objectArray; let index = index">
<app-child [inputObject]="objectArray[index]"></app-child> // does not maintain "selected" property
</div>
<div>
<app-child [inputObject]="objectArray[0]"></app-child> // DOES maintain "selected" property
</div>
<button (click)="changeAnObject()">Change Object</button>
<div (click)="selected = !selected">
a: {{inputObject.a}}
b: {{inputObject.b}}
SELECTED: {{selected}}
</div>
In the parent HTML, [inputObject]="objectArray[0]"
is the only solution I've found which maintains the other properties of Child when changing the element in objectArray[0]
.
This is not good enough for me as I have many objects to display.
Is there a better way to send data into Components without resetting them entirely?
I have attempted using Angular Accessors
with @Input() set inputObject {...}
but it has not worked to maintain the Component's properties. That is, the constructor executes again when inputObject
changes, resetting all properties to default values.
Upvotes: 1
Views: 1409
Reputation: 439
You need to track by your object by some index, that will not change after you execute your changeAnObject action.
<div *ngFor="let object of objectArray; let index = index; trackBy: trackByFn">
with your trackByFn being:
trackByFn(index, item) {
return item.a;
}
Just do it like this and it will work! :)
What it does is that by tracking the object by an unique and non changing id, it will not reiterate through the ngFor loop because it detected that the id that is tracking the loop has not been changed
My example was based on your stackBlitz
Upvotes: 2