首页 文章

Angular - 从父组件向动态子组件发出事件

提问于
浏览
1

编辑:我采取了不同的方法来解决这个问题:根据接受的答案,在 save() 上检查父级中的动态子组件值 .

我正在尝试让一个父组件发出一个事件/可观察对象,以便它的子动态组件在听到它时触发一个动作 .

我已经了解到,使用动态组件的 @Input()@Output() 装饰器是不可能的,所以......

这是我的用例概述:

  • 动态子组件由一组4个输入元素组成 . (完成)

  • 父组件具有 Add 按钮,用于添加动态子组件 . 此按钮可用于添加动态子组件的任意数量的实例 . (完成)

  • 动态子组件具有 Delete 按钮以删除其实例 . (完成)

  • 父组件具有Array类型的属性 . 每个数组项都是包含动态组件输入值的对象 . (去做)

  • 父组件具有 Save 按钮,单击该按钮应将事件发送到动态组件实例,因此每个组件都可以将其输入值保存为对象 . (即3个实例=> [ {a:..., b:..., c:..., d:...}, {...}, {...} ] ; 5个实例=> 5个数组项,依此类推) . (去做)

我正在尝试从“保存”按钮(上面的#5)发出父事件,并让动态子组件的每个现有实例监听事件,然后对父数组执行 .push 操作(上面的#4) .

可能这不是最佳实践,但还没有设计任何其他方法来确保在发生可能不确定的随机数量的添加/删除实例操作之后为现有动态组件实例保存值 .

Parent Component:

HTML

...
<button (click)="addDetailRow()" type="button">Add Detail Row</button>
<div #detailContainer></div>
...
<button (click)="save()">Save</button>
...

打字稿

...
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: here emit an event/observable
}
...

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>

打字稿

...
detail_item: { [key: string]: any; } = {};
detailRowArray: Array<Object>;
...
removeRow() {
  ...
}
...
// TODO: trigger this function when parent emits event/observable
saveToParentArray() {
     this.detailRowArray.push(this.detail_item);
}

附:代码库使用模板驱动的形式,因此不可能在其中使用FormArray,(我只是熟悉angular 2) . 感谢您的关注 .

2 回答

  • 1

    好的,我采取了不同的解决方案:

    在对所提供的选项进行一些研究之后,我不再希望将事件从父级发送到动态子组件实例;

    相反,我 grab 现有的 ViewContainerRef 变量,并沿着 for 循环使用其API,我检索了动态组件实例,从中我检索了4个输入元素的集合,然后以编程方式构造了预期的对象,并将其作为项目推送到parent的 detailRowArray 数组 . 问题解决了 .

    下面是代码的简化版本:

    save() {
        // Temporary variables to construct array of arrays
        let parentNodeArray: any[] = [];
        let inputs: any[] = [];
        // loop to retrieve each existing instance of the dynamic component into temp variable
        for (let i = 0; i < this.container.length; i++) {
          let comp: any;
          comp = this.container.get(i);
          parentNodeArray.push(comp.rootNodes[0]);
    
        }
        // loop to retrieve values from the set of 4 input elements per instance
        // into temp array var (mixed with good ol' JS)
        parentNodeArray.forEach((elem: any) => {
          inputs.push( Array.prototype.slice.call( elem.querySelectorAll('input') ).map(node => {
            return node.value; });
          );
        });
    
  • 0

    方法1:

    数据数组可以存在于父组件和子组件中,接受它作为输入并对其进行修改 .

    方法2:

    理想情况下(如评论中已提到的)你应该以另一种方式做到这一点 . 当用户将数据输入子组件时,我们可以触发从子级到父级的事件

    方法3:

    但是,如果您仍希望从父组件中执行子组件中的某些操作,则只需调用子组件实例并调用它们即可 .

    detailRowComp[1].instance.saveToParentArray()
    

    但这是多余的,不是一个好的做法 . 选择以上两种中的一种 .

相关问题