角度动态组件 parent-chld 通讯

angular5 dynamic compoments parent-chld communication

我正在实施 the dynamic compoment docs 中描述的方法。

我需要我的动态组件能够向 parent 组件发出事件,作为响应,parent 组件可能需要调用 child 组件的方法。

当 child 组件位于 parent 的模板中时,我知道如何将 child 事件绑定到 parent 的方法:

但是在动态组件方法中,parent 模板包含一个指令,该指令反过来将包装动态实例化的组件。

如何在动态组件上设置@Input 和@Output 属性并将它们从parent 传播到child 和vice-versa?

此外,我怎样才能让 parent 调用 child 上的方法?

就动态组件而言,angular 文档有点过时了。看一下 Angular 4 中引入的 [ngComponentOutlet] 指令。它可能会大大简化您的组件。

简单用例如下:

import { Component } from '@angular/core';
import { HelloComponent } from './hello.component';

@Component({
  selector: 'my-app',
  template: `
    <ng-container [ngComponentOutlet]="component"></ng-container>
  `,
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  // [ngTemplateOutlet] binds to this property, you can set this dynamically!
  component = HelloComponent; 
}

api documentation.

中有关 NgComponentOutlet 的更多信息

所以这是个好消息。坏消息是目前无法访问以这种方式创建的组件的 @Inputs@Outputs。您可以在 github.

上跟踪此 issue

同时,有人建议使用 ng-dynamic-component

您还可以使用共享服务实现 parent/child 通信:

app.component.ts

import { Component } from '@angular/core';
import {CommunicationService} from './communication.service';
import {HelloComponent} from './hello.component';

@Component({
  selector: 'my-app',
  template: `
  <input (keydown.enter)="send(input.value); input.value = ''" #input />
  <ng-container [ngComponentOutlet]="component"></ng-container>
  `,
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  component = HelloComponent;

  constructor(private communicationService: CommunicationService) {}

  send(val: string) {
    this.communicationService.next(val);
  }
}

communication.service.ts

import {Injectable } from '@angular/core';
import {Subject} from 'rxjs/Subject';
import  {Observable } from 'rxjs/Observable';

@Injectable()
export class CommunicationService {
  private messageSource = new Subject();
  message$ = this.messageSource.asObservable();

  next(val: string) {
    this.messageSource.next(val);
  }
}

hello.component.ts

import { Component, Input } from '@angular/core';
import {Observable} from 'rxjs/Observable';
import {CommunicationService} from './communication.service';

@Component({
  selector: 'hello',
  template: `<h1>{{ message$ | async }} </h1>`,
  styles: [`h1 { font-family: Lato; }`]
})
export class HelloComponent  {
  message$: Observable<string>;

  constructor(private communication: CommunicationService) {
    this.message$ = communication.message$;
  }
}

Live demo