Angular 2将组件实例动态添加到容器中 [英] Angular 2 dynamically add component instance into container

查看:55
本文介绍了Angular 2将组件实例动态添加到容器中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在Angular 2中实现ComponentContainer,以便您可以动态添加其他组件,例如Android中的LinearLayout.

I'm trying to implement in Angular 2 a ComponentContainer so you can dynamically add other Components, similar to, for example, a LinearLayout in Android.

到目前为止,使用带有用户单击所选组件的Angular 2动态选项卡我可以动态添加通过类型的组件.

So far, using Angular 2 dynamic tabs with user-click chosen components I can dynamically add Components passing the Type.

我的问题是,使用这种方法,创建的组件仅由其类型创建,而我不知道如何为其提供参数.

My problem is that using this method, the created Component is created only by its Type and I don't know how to give arguments to it.

这就是我所做的:

container.component.ts

import {
    Component,
    OnChanges,
    AfterViewInit,
    OnDestroy,
    Input,
    Type,
    ViewChild,
    ViewContainerRef,
    ComponentRef,
    ComponentResolver,
    ComponentFactory
} from '@angular/core';

@Component({
    selector: 'wrapper-component',
    template: '<div #container></div>'
})
class WrapperComponent implements OnChanges, AfterViewInit, OnDestroy {

    @Input() type: Type;
    @ViewChild('container', {read: ViewContainerRef}) container;

    cmpRef: ComponentRef<any>;

    private isViewInitialized: boolean = false;

    constructor(private resolver: ComponentResolver) { }

    private updateComponent() { 
        if(!this.isViewInitialized)
            return;

        if(this.cmpRef)
            this.cmpRef.destroy();

        this.resolver.resolveComponent(this.type).then((factory: ComponentFactory<any>) => {
            this.cmpRef = this.container.createComponent(factory);
        })
    }

    ngOnChanges() {
        this.updateComponent();
    }

    ngAfterViewInit() {
        this.isViewInitialized = true;
        this.updateComponent();
    }

    ngOnDestroy() {
        if(this.cmpRef)
            this.cmpRef.destroy();
    }
}

@Component({
    selector: 'container-component',
    template: `
        <wrapper-component 
            *ngFor="let element of elements" 
            [type]="element">
        </wrapper-component>
    `,
    directives: [WrapperComponent]
})
export class ContainerComponent {

    private elements: Type[] = [];    

    visibility: boolean = true;

    Add(element: Type) {
        this.elements.push(element);
    }

    AddAll(elements: Type[]) {
        elements.forEach(element => {
            this.Add(element);
        });
    }

    Clear() {
        this.elements = [];
    }
}

a1.component.ts

import { Component, Type, ViewChild } from '@angular/core'
import { ContainerComponent } from '../../components/container.component';

@Component({
    selector: 'child-component',
    template: '<div>a{{text}}</div>'
})
class ChildComponent {
    text: string;
}

@Component({
    selector: 'a1step',
    template: `
        <button (click)="onClick()">Add</button>
        <container-component #container></container-component>
    `,
    directives: [ContainerComponent]
})
export class A1Step {
    @ViewChild('container') container : ContainerComponent;

    onClick() {
        this.container.Add(ChildComponent);
    }
}

我可以在此处动态添加ChildComponents,但是如何设置其文本?

Here I can dynamically add ChildComponents, but how can I set its text?

我不知道是否对其他人有用,但是为ChildComponent定义了一个参数类,并将ContainerComponent的elements数组更新为包含特定args的对象数组,我可以轻松地将特定参数传递给ChildComponents:

I don't know if could be useful to others, but defining an argument class for the ChildComponent and updating the elements array of the ContainerComponent as an array of objects containing the specific args, I can easily pass specific arguments to the ChildComponents:

container.component.ts

import {
    Component,
    OnChanges,
    AfterViewInit,
    OnDestroy,
    Input,
    Type,
    ViewChild,
    ViewContainerRef,
    ComponentRef,
    ComponentResolver,
    ComponentFactory
} from '@angular/core';

export class ChildArgs {
    type: Type;
    args: any;
}

@Component({
    selector: 'wrapper-component',
    template: '<div #container></div>'
})
class WrapperComponent implements OnChanges, AfterViewInit, OnDestroy {

    @Input() argsElement: ChildArgs;
    @ViewChild('container', {read: ViewContainerRef}) container;

    cmpRef: ComponentRef<any>;

    private isViewInitialized: boolean = false;

    constructor(private resolver: ComponentResolver) { }

    private updateComponent() { 
        if(!this.isViewInitialized)
            return;

        if(this.cmpRef)
            this.cmpRef.destroy();

        this.resolver.resolveComponent(this.argsElement.type).then((factory: ComponentFactory<any>) => {
            this.cmpRef = this.container.createComponent(factory);
            this.cmpRef.instance.args = this.argsElement.args;
        })
    }

    ngOnChanges() {
        this.updateComponent();
    }

    ngAfterViewInit() {
        this.isViewInitialized = true;
        this.updateComponent();
    }

    ngOnDestroy() {
        if(this.cmpRef)
            this.cmpRef.destroy();
    }
}

@Component({
    selector: 'container-component',
    template: `
        <wrapper-component 
            *ngFor="let argsElement of argsElements" 
            [argsElement]="argsElement">
        </wrapper-component>
    `,
    directives: [WrapperComponent]
})
export class ContainerComponent {

    private argsElements: ChildArgs[] = [];

    AddArgsElement(argsElement: ChildArgs) {
        this.argsElements.push(argsElement);
    }
}

a1.component.ts

import { Component, Type, ViewChild } from '@angular/core'
import { ContainerComponent, ChildArgs } from '../../components/container.component';

class ChildComponentArgs {
    text: string;
}

@Component({
    selector: 'child-component',
    template: '<div>a{{args.text}}</div>'
})
class ChildComponent {
    args: ChildComponentArgs;
}

class ChildComponent2Args {
    text: string;
}

@Component({
    selector: 'child-component2',
    template: '<div>b{{args.text}}</div>'
})
class ChildComponent2 {
    args: ChildComponent2Args;
}

@Component({
    selector: 'a1step',
    template: `
        <button (click)="onClick()">Add</button>
        <button (click)="onClick2()">Add2</button>
        <container-component #container></container-component>
    `,
    directives: [ContainerComponent]
})
export class A1Step {
    @ViewChild('container') container : ContainerComponent;

    private cnt: number = 0;
    private cnt2: number = 0;

    onClick() {
        let childComponentArgs: ChildComponentArgs = new ChildComponentArgs();
        childComponentArgs.text = "" + ++this.cnt; 

        let childArgs: ChildArgs = new ChildArgs();
        childArgs.type = ChildComponent;
        childArgs.args = childComponentArgs;

        this.container.AddArgsElement(childArgs);
    }

    onClick2() {
        let childComponentArgs: ChildComponent2Args = new ChildComponent2Args();
        childComponentArgs.text = "" + ++this.cnt2; 

        let childArgs: ChildArgs = new ChildArgs();
        childArgs.type = ChildComponent2;
        childArgs.args = childComponentArgs;

        this.container.AddArgsElement(childArgs);
    }
}

推荐答案

您可以使用 cmpRef.instance 访问已创建的组件实例:

You can access the created component instance using cmpRef.instance:

   this.resolver.resolveComponent(this.type).then((factory: ComponentFactory<any>) => {
        this.cmpRef = this.container.createComponent(factory);
        this.cmpRef.instance.text = this.someText;
    })

另请参见 Angular 2动态标签用户单击选定的组件以获取完整示例.

See also Angular 2 dynamic tabs with user-click chosen components for a full example.

这篇关于Angular 2将组件实例动态添加到容器中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆