【问题标题】:Angular 2: contentChildren communicationAngular 2:内容儿童交流
【发布时间】:2017-07-30 21:44:45
【问题描述】:

在 contentChildren 与其“父级”之间进行通信的首选方法是什么?

更新:孩子可能不是直接父母...

给定一个随机的孩子列表,由一组包裹:

<child-group>
    <div>Some other content, child may not be direct parent...</div>
    <child *ngFor="let item of data$ | async;"></child>
</child-group>

子组件:

@Component({
    selector: 'child',
    template: '<button (click)="didSomethingTellGroup()"></button>',
    styleUrls: ['child.component.scss'],
})
export class ChildComponent implements OnInit {

    constructor() {
    }

    ngOnInit() {

    }

    doSomething() {
        console.log('Called from group component')
    }

    didSomethingTellGroup() {
        //EventEmitter?
        //Observable?
    }

}

父组件:

@Component({
    selector: 'child-group',
    template: '<ng-content></ng-content>',
    styleUrls: ['child-group.component.scss'],
})
export class ChildGroupComponent implements AfterContentInit {
    @ContentChildren(ChildComponent) childrenList: QueryList<ChildComponent>;

    constructor() {
    }

    ngAfterContentInit() {
        //How to invoke doSomething() on all children?
        childrenList...

        //How can I get notification from one or all children, that it did something, or its state has changed.
        childrenList...
    }
}

如何从 ChildGroup 调用子方法? Child 如何将信息发送回 ChildGroup?

更新:

在下面的 cmets 中,我提到当我试图对孩子调用一个方法时,什么也没发生。好吧,事实证明我需要订阅更改并等待孩子们......然后我就可以调用

ngAfterContentInit()
{
    this.childrenList.changes
        .subscribe(list => {
                list.forEach(c => c.doSomething())
            }
        );
}

【问题讨论】:

  • 你可以在child上创建一个函数,你可以在childrenList上调用循环,同样你可以创建一个eventemitter,你可以在parent中订阅。

标签: angular angular2-template


【解决方案1】:

对于您的孩子到父母的场景,@Output 事件发射器是您最好的选择。您的子组件正在将其自身的内部操作(用户单击某处)转换为该组件的任何用户都可以侦听的业务相关事件。

至于父母打电话给孩子,您的示例已经完成了大部分工作。只需遍历 QueryList 并在子组件上调用您希望的任何方法。

ngAfterContentInit() {    
  //How to invoke     doSomething() on all children?  
  this.childrenList.forEach ( c => c.doSomething(); ) 
   ...
}

【讨论】:

  • 我忘了表明孩子可能是也可能不是直接父母,@Ouput 还能用吗?我会更新我的问题..
  • 如果它不是直接孩子,那么不,您必须手动将事件向上冒泡,或者使用服务来代理通信
  • 感谢您的回复。我尝试调用 callMethod(),但没有任何反应。注销 this.childrenList.length 会导致 0.. 对于服务,我如何保证该服务仅对这组子/组是唯一的,因为我可以在页面上有多个子组。甚至嵌套...
  • 查看我上面的回答(和评论);-)
【解决方案2】:

前面的答案是完全正确的,使用@Output 并循环通过你的QueryList 是要走的路,但如果,正如你提到的,你的孩子不是直接的,你可以使用服务作为沟通渠道.

这是一个非常基本的 plunker 演示:http://plnkr.co/edit/VuYiz7gVB42PEnnk2d8C(我不是 observables 方面的专家,所以也许可以改进)。

基本上,当您单击子组件的按钮时,它会使用:

this.myService.sendToParent(this.random);

通过服务向父母发送消息。在这个函数中,服务通过 observable 向父级发送消息:

this.parentSubject.next(value);

之前,父级订阅了这个 observable:

this.service.getParentMessages().subscribe((data) =>
{
  alert('Something changed from a children: ' + data);

  this.service.sendToChildren(data);
});

如您所见,当它收到一个新值时,它使用函数sendToChildren 通过服务向他的所有孩子发送消息(同样的原理适用)。当孩子收到消息时,它会更改最终显示在组件中的值。

【讨论】:

  • 感谢您的精心回复。我如何确保所使用的服务对于特定组是唯一的?这是 viewProvider 会出现的地方吗?
  • 我编辑了我的 plunker 来向您展示如何做到这一点。基本上,我没有在应用程序模块中导入提供程序,而是在父组件中导入了它,这样,为该类型的每个组件创建了一个新的服务实例。有关更多信息,请参阅这个很棒的答案:stackoverflow.com/questions/35888434/…
  • 也许我应该为此提出一个新问题,但是当我在父级中移动提供者时出现此错误:未处理的承诺拒绝:MyService 没有提供者! ;区域:角度;任务:Promise.then - 我今天确实升级到了 Angular 4,不确定那里是否有区别。但是,在我的应用程序中,我使用延迟加载,并且这个父/子是模块的一部分,我只是在父组件中导入它,这确实是我唯一需要导入它的地方吗?不知道我哪里出错了......谢谢
  • 如你所说,如果可能的话,最好与管道工一起创建一个新问题
  • 我会解决这个问题的,谢谢。但如果你能澄清一件事。现在看来我需要嵌套这些“子组”。当我与您的 plunker 一起尝试时,我不清楚嵌套组如何或是否共享服务的唯一实例,或者它是否来自父“子组”..?再次感谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-30
  • 2018-07-06
  • 2017-03-16
相关资源
最近更新 更多