在Angular 2组件中,如何让孩子不知道对象的种类?

时间:2017-04-14 09:59:17

标签: angular children

在我的父组件中,我可以在其内容中添加两种类型的组件:子组件-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 中的孩子?

1 个答案:

答案 0 :(得分:0)

如果您不知道要定位的组件的类,则无法使用@ContentChild()@ContentChildren()但您可以使用共享服务在子级和父级之间进行通信,或者您可以注入父级子:

共享服务方法:

SharedService

@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

这里只有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]);
    }

}

ChildA / ChildB

@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组件的情况下使用ChildBParent,则只需将此参数标记为进样器的可选项:

    export class ChildA {
        constructor(@Optional() private parent: ParentComponent) {}
    }
    
  • 您可能会遇到一些循环依赖SharedService需要ChildAChildA需要SharedService。您可以通过创建将在服务或父组件中使用的接口(取决于您选择的方法)来表示ChildA / ChildB类或在同一文件中声明这些类,从而避免这种情况模块。

  • 我使用ChildA|ChildB类型来实现简洁,如果ChildAChildB具有共同的祖先,或者两者都实现了接口,例如:IChild或{{1最好使用AbstractChildAbstractChild类型。