在我的父组件中,我可以在其内容中添加两种类型的组件:子组件-A 和子组件-B ...所以,我们可以有几种可能性:
<parent-component>
<child-component-A></child-component-A>
<child-component-A></child-component-A>
</parent-component>
或/和
<parent-component>
<child-component-B></child-component-B>
<child-component-B></child-component-B>
</parent-component>
或/和
<parent-component>
<child-component-A></child-component-A>
<child-component-B></child-component-B>
</parent-component>
如何使用 @ content-children 之类的内容 parent.component.ts 中的孩子?
答案 0 :(得分:0)
如果您不知道要定位的组件的类,则无法使用@ContentChild()
或@ContentChildren()
但您可以使用共享服务在子级和父级之间进行通信,或者您可以注入父级子:
@Injectable()
export class SharedService {
private childrenEvents = new ReplaySubject < ["add" | "remove", ChildA | ChildB] > ();
children: Observable < [ChildA | ChildB] >
constructor() {
let output: [ChildA | ChildB]=[];
this.children = Observable.merge(
this.childrenEvents.filter(([action, child]) => action === "add").do(([action, child]) => output = output.concat(child)),
this.childrenEvents.filter(([action, child]) => action === "remove").do(([action, child]) => output = output.filter(item => item !== child))
).map(() => output).publishBehavior([]);
this.children.connect();
}
addChild(child: ChildA | ChildB) {
this.childrenEvents.next(["add", child]);
}
removeChild(child: ChildA | childB) {
this.childrenEvents.next(["remove", child]);
}
}
@Component({
template: "<ng-content></ng-content>",
selector: "parent"
})
export class ParentComponent implements OnInit, OnDestroy {
private sub: Subscription;
constructor(private sharedService: SharedService) {}
ngOnInit() {
this.sub = this.sharedService.children.subscribe(children => {
console.log(children)
})
}
ngOnDestroy() {
this.sub.unsubscribe();
}
}
这里只有ChildA,但它与ChildB的行为相同。
@Component({
template: "child a component",
selector: "child-a"
})
export class ChildA implements OnInit, OnDestroy {
private sub: Subscription;
constructor(private sharedService: SharedService) {}
ngOnInit() {
this.sharedService.addChild(this);
}
ngOnDestroy() {
this.sharedService.removeChild(this);
}
}
只需在子节点中注入ParentComponent即可避免使用服务。
@Component({
template: "<ng-content></ng-content>",
selector: "parent"
})
export class ParentComponent implements OnInit,OnDestroy{
private childrenEvents = new ReplaySubject < ["add" | "remove", ChildA | ChildB] > ();
children: Observable < [ChildA | ChildB] >
constructor() {
let output: [ChildA | ChildB]=[];
this.children = Observable.merge(
this.childrenEvents.filter(([action, child]) => action === "add").do(([action, child]) => output = output.concat(child)),
this.childrenEvents.filter(([action, child]) => action === "remove").do(([action, child]) => output = output.filter(item => item !== child))
).map(() => output).publishBehavior([]);
this.children.connect();
}
ngOnInit() {
this.sub = this.sharedService.children.subscribe(children => {
console.log(children);
})
}
ngOnDestroy() {
this.sub.unsubscribe();
}
addChild(child: ChildA | ChildB) {
this.childrenEvents.next(["add", child]);
}
removeChild(child: ChildA | childB) {
this.childrenEvents.next(["remove", child]);
}
}
@Component({
template: "child a component",
selector: "child-a"
})
export class ChildA implements OnInit, OnDestroy {
private sub: Subscription;
constructor(private parent: ParentComponent) {}
ngOnInit() {
this.parent.addChild(this);
}
ngOnDestroy() {
this.parent.removeChild(this);
}
}
备注强>:
如果您希望能够在没有ChildA
组件的情况下使用ChildB
或Parent
,则只需将此参数标记为进样器的可选项:
export class ChildA {
constructor(@Optional() private parent: ParentComponent) {}
}
您可能会遇到一些循环依赖SharedService
需要ChildA
和ChildA
需要SharedService
。您可以通过创建将在服务或父组件中使用的接口(取决于您选择的方法)来表示ChildA
/ ChildB
类或在同一文件中声明这些类,从而避免这种情况模块。
我使用ChildA|ChildB
类型来实现简洁,如果ChildA
和ChildB
具有共同的祖先,或者两者都实现了接口,例如:IChild
或{{1最好使用AbstractChild
或AbstractChild
类型。