UPDATE: I've decided to tackle this issue in a different way by retrieving dynamic child component values in the parent component's save()
function, following the accepted answer.
I am attempting to create a system where a parent component emits an event or observable that triggers actions in its dynamic child components when they listen for it.
I have discovered that using the @Input()
and @Output()
decorators with dynamic components is not possible, so...
Here is an overview of my current scenario:
- The dynamic child component contains a group of 4 input elements. (completed)
- The parent component has an
Add
button that adds instances of the dynamic child component. This button can be used to add multiple instances of the dynamic child component. (completed) - Each dynamic child component has a
Delete
button to remove its own instance. (completed) - The parent component possesses a property that is an Array of objects. Each item in the array is an object containing the input values of the dynamic child component. (pending)
- The parent component also has a
Save
button, which when clicked should emit an event to the dynamic child component instances, allowing each one to save their input values as objects. (e.g. 3 instances =>
; 5 instances => 5 array items, and so on). (pending)[ {a:..., b:..., c:..., d:...}, {...}, {...} ]
I am aiming to emit the parent event from the Save button (#5 above) and have each existing dynamic child component instance listen to the event and execute a .push
operation on the parent array (#4 above).
This might not be considered best practice, but I haven't yet devised another method to ensure that the values are saved for the existing dynamic component instances after potentially numerous, random add/remove instance actions have been performed.
Parent Component:
html
...
<button (click)="addDetailRow()" type="button">Add Detail Row</button>
<div #detailContainer></div>
...
<button (click)="save()">Save</button>
...
typescript
...
detailRowArray: Array<Object>;
...
addDetailRow() {
let comp = this._cfr.resolveComponentFactory(DetailRowComponent);
let detailRowComp = this.container.createComponent(comp);
detailRowComp.instance._ref = detailRowComp;
detailRowComp.instance.detailRowArray = this.detailRowArray;
}
save() {
// TODO: emit an event/observable here
}
...
Dynamic Child Component:
html
<div><input type="text" name="a" [(ngModel)]="detail_item.a" #a></div>
<div><input type="text" name="b" [(ngModel)]="detail_item.b" #b></div>
<div><input type="text" name="c" [(ngModel)]="detail_item.c" #c></div>
<div>
<input type="text" name="d" [(ngModel)]="detail_item.d" #d>
<span>
<button (click)="removeRow()">Remove Row</button>
</span>
</div>
typescript
...
detail_item: { [key: string]: any; } = {};
detailRowArray: Array<Object>;
...
removeRow() {
...
}
...
// TODO: call this function when the parent emits an event/observable
saveToParentArray() {
this.detailRowArray.push(this.detail_item);
}
P.S. The codebase utilizes template-driven forms, so using FormArray or similar constructs is not feasible at the moment. Thanks for your attention. (I'm still getting familiar with Angular 2+).