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

时间:2018-04-20 01:27:13

标签: angular typescript eventemitter

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

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

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

这是我的用例概述:

  1. 动态子组件由一组4个输入元素组成。 (完成)
  2. 父组件具有Add按钮,用于添加动态子组件。此按钮可用于添加动态子组件的任意数量的实例。 (完成)
  3. 动态子组件具有Delete按钮以删除其实例。 (完成)
  4. 父组件具有Array of objects类型的属性。每个数组项都是包含动态组件输入值的对象。 (待办事项)
  5. 父组件具有Save按钮,单击该按钮应将事件发送到动态组件实例,因此每个组件都可以将其输入值保存为对象。 (即3个实例=> [ {a:..., b:..., c:..., d:...}, {...}, {...} ]; 5个实例=> 5个数组项,依此类推)。 (待办事项)
  6. 我尝试从“保存”按钮(上面的#5)发出父事件,并让动态子组件的每个现有实例都听取该事件,然后对该事件执行.push操作。父数组(上面#4)。

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

    父组件:

    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
    }
    ...
    

    动态子组件:

    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);
    }
    

    P.S。代码库使用模板驱动的形式,因此不可能在其中使用FormArray,(我只是熟悉angular 2 +)。谢谢你的关注。

3 个答案:

答案 0 :(得分:1)

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

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

相反,我抓住了现有的ViewContainerRef变量,并在for循环中使用其API检索了动态组件实例,从中我检索了4个输入元素的集合,然后以编程方式构造了预期的对象,并将其作为项目推送到父的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; });
      );
    });

答案 1 :(得分:0)

方法1:

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

方法2:

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

方法3:

但是,如果你仍想在父的子组件中执行,那么你可以调用子组件实例并调用它们。

detailRowComp[1].instance.saveToParentArray()

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

答案 2 :(得分:0)

使用对象而不是数字或字符串变量来用动态值更新子组件。