2017-03-09 87 views
2

contentChildren与其“父”之间的首选通信方式是什么?Angular 2:contentChildren communication

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

鉴于儿童的随机列表,由一组包装:

<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中调用子方法?一个孩子怎么能把信息发回给ChildGroup?

UPDATE:

在下面我提到的,当我尝试调用对孩子没有什么方法正在发生的意见。那么事实证明,我需要订阅的变化,等待孩子......然后我就能够调用

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

你可以在child上创建一个函数,你可以调用childrenList循环,类似的,你可以创建一个你可以在父类中订阅的eventemitter。 –

回答

3

以前的答案是完全正确的,使用@Output和循环通过你的QueryList是要走的路,但如果像你所说,你的孩子是不是直接的,你可以使用一个服务作为通信香奈儿。

这里是一个非常基本的蹲跳者演示这个:http://plnkr.co/edit/VuYiz7gVB42PEnnk2d8C(我不是专家,所以也许这可能会得到改善)。

基本上,当你点击你的孩子组成的一个按钮,它使用:

this.myService.sendToParent(this.random); 

通过服务发送消息到父。在此功能,该服务通过可观察到的将消息发送到父:

this.parentSubject.next(value); 

此前,父母订阅此观察到:

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

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

正如你所看到的,当它接收到一个新的价值,它使用功能sendToChildren通过服务向他的所有子女发送消息(当时适用相同的原则)。当孩子接收到消息时,它会更改最终显示在组件中的值。

+0

谢谢你的详细答复。我如何确保所使用的服务对于特定组是唯一的?这是viewProvider会进来吗? – Thibs

+0

我编辑了我的蹦床,告诉你如何做到这一点。基本上,我不是在应用程序模块中导入提供程序,而是将它导入到父组件中,这样就为该类型的每个组件创建了一个新的服务实例。欲了解更多信息,请参阅这个真棒回答:http://stackoverflow.com/questions/35888434/what-are-viewproviders-in-angular-2-and-what-is-the-difference-bw-providers-vs – ssougnez

+0

也许我应该为此启动一个新问题,但是当我将提供程序移动到父级时,出现此错误:未处理的Promise拒绝:没有MyService提供程序! ;区域:角度;任务:Promise.then - 我今天碰到了Angular 4,不知道那里是否有区别。但是,在我的应用程序中,我使用延迟加载,并且此父/子是模块的一部分,我只将它导入父组件,这确实是我需要导入它的唯一位置?不知道我去哪里错了......谢谢 – Thibs

3

为您的孩子父母的情况下,一个@Output事件发射器是你最好的选择。您的子组件正在将内部操作(用户单击某处)转换为该组件的任何用户都可以监听的业务相关事件。

至于父母打电话的孩子,你已经是你的榜样的大部分方式。只需遍历QueryList并调用您希望在您的子组件上使用的任何方法即可。

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

我忘记了显示孩子可能是也可能不是直系父母,那么@Ouput仍然会工作吗?我会更新我的问题.. – Thibs

+0

如果它不是一个直接的孩子,那么不是,你必须手动将事件向上拉链,或使用服务来中介通信 – snorkpete

+0

感谢您的答复。我试着调用callMethod(),但没有任何反应。注销this.childrenList.length结果为0 .. 对于服务,我怎么能保证该服务对于这组子/只是唯一的,因为我可以在页面上有多个子组。甚至嵌套... – Thibs