孩子在Angular 2中收听父事件


81

在Angular文档中,有一个关于侦听父母的孩子事件的主题。没关系。但是我的目的是相反的!在我的应用程序中,有一个“ admin.component”保存着管理页面的布局视图(侧边栏菜单,任务栏,状态等)。在此父组件中,我配置了路由器系统以在管理员的其他页面之间更改主视图。问题是要在更改后保存内容,用户单击任务栏上的“保存”按钮(位于admin.component中),并且子组件必须侦听该click事件以执行保存人员。


2
听起来,这样做的最佳实践是使用服务和可观察的事件调度。
zpul

您的问题与这一问题并不太相似:stackoverflow.com/questions/35560860/…–
freethebees

@freethebees也许解决方法相同,但是问题的形式不同,我的目的是找到解决这种情况的最佳方法。
Hamed Hamedi

我们不会为传递给子组件的单个事件设置服务。
Ben Racicot

Answers:


98

我认为该文档可能对您有所帮助:

实际上,您可以利用父级提供给子级的可观察/主题。像这样:

@Component({
  (...)
  template: `
    <child [parentSubject]="parentSubject"></child>
  `,
  directives: [ ChildComponent ]
})
export class ParentComponent {
  parentSubject:Subject<any> = new Subject();

  notifyChildren() {
    this.parentSubject.next('some value');
  }
}

子组件可以简单地订阅此主题:

@Component({
  (...)
})
export class ChildComponent {
  @Input()
  parentSubject:Subject<any>;

  ngOnInit() {
    this.parentSubject.subscribe(event => {
      // called when the notifyChildren method is
      // called in the parent component
    });
  }

  ngOnDestroy() {
    // needed if child gets re-created (eg on some model changes)
    // note that subsequent subscriptions on the same subject will fail
    // so the parent has to re-create parentSubject on changes
    this.parentSubject.unsubscribe();
  }

}

否则,您可以通过类似的方式利用包含此类主题的共享服务。


除非父组件从ngInit内部广播下一个值,否则子组件中的回调将不会运行。为什么会这样?
cjsimon

4
与ViewChild相比,使用此方法有什么优势?
sunnyiitkgp

尽管它看起来更专业,但是在我的情况下花了几个小时进行试验之后,我在添加/删除子元素(从而取消订阅该主题)时摆脱UnsubscribeErrors的麻烦。因此,通过TimeBoxing,我获得了@StephenPaul更为直接的答案。无论如何,谢谢您的回答,可能只是我现在对rxjs库的了解不够,无法完全理解它,并对示例进行正确(额外)的调整以使其完美无缺。
Bernoulli IT

115

为了后代,我以为我要提到更常规的解决方案:只需获取对ViewChild的引用,然后直接调用其方法之一即可。

@Component({
  selector: 'app-child'
})
export class ChildComponent {

  notifyMe() {
    console.log('Event Fired');
  }
}

@Component({
  selector: 'app-parent',
  template: `<app-child #child></app-child>`
})
export class ParentComponent {

  @ViewChild('child')
  private child: ChildComponent;

  ngOnInit() {
    this.child.notifyMe();
  }
}

3
一旦输入父组件,它就会崩溃Cannot read property 'notifyMe' of undefined
亲切的用户

1
与@ThierryTemplier某种程度上更专业的感觉解决方案相比,选择了这种非常直观的解决方案(请参阅此处的我的评论)。
Bernoulli IT

2
@BernoulliIT,您的观点很好。我想他们最终会完成大致相同的任务。我的解决方案使用更少的代码。他的解决方案意味着父组件不必注入子组件即可向其发送消息。RXJS很棒,但是我经常在Angular项目中经常看到它的过度使用。人们认为这是“银弹”之类的东西。实际上,它会使事情变得复杂得多。看看他的ngOnDestroy()方法里面的评论。就我而言,那太模糊了。那只是一个等待恕我直言的错误。
斯蒂芬·保罗

1
“在ngOnDestroy()方法中查看他的评论。” 我认为这正是我尝试该方法时所遭受的“痛苦”,然后我陷入困境,没有足够的时间进行进一步的调查(对于我从事的商业项目)。尽管它“使我的专业心脏有些受伤;”
Bernoulli IT

1
谢谢@StephenPaul,对我来说,“父级调用Viewchild”方法很好,但是您的回答帮助我实现了自己的命运!
MKJ

13

如果我正确地理解了这个问题,那么在这里可能会采取更裸露的方法。假设-

  • OP在父组件中具有一个保存按钮
  • 需要保存的数据在子组件中
  • 子组件可能需要的所有其他数据可以从服务中访问

在父组件中

<button type="button" (click)="prop1=!prop1">Save Button</button>
<app-child-component [setProp]='prop1'></app-child-component>

并在孩子..

prop1:boolean;
  @Input()
  set setProp(p: boolean) {
    // -- perform save function here
}

这只是将按钮单击发送到子组件。从那里子组件可以独立保存数据。

编辑:如果父模板中的数据也需要与单击按钮一起传递,则使用此方法也是可能的。让我知道是否是这种情况,我将更新代码示例。


0

对于那些正在 Cannot read property 'notifyMe' of undefined

尝试在ngAfterViewInit()intead中调用方法ngOnInit()

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.