Angular 2.1.0动态动态创建子组件

我正在尝试做的angular2.1.0是动态创建子组件,这些子组件应该注入到父组件中。例如父组件是lessonDetails包含共享的内容为所有课程如如按钮Go toprevious lessonGo to next lesson和其他东西。根据路线参数,应将作为 课程内容动态注入到。子组件(课程内容)的HTML定义为外部某处的纯字符串,它可以是类似以下内容的对象:

export const LESSONS = {

"lesson-1": `<p> lesson 1 </p>`,

"lesson-2": `<p> lesson 2 </p>`

}

通过innerHtml在 模板中进行以下操作可以轻松解决问题。

<div [innerHTML]="lessonContent"></div>

在每次更改路线参数时,lessonContent父组件的属性都会更改(内容(新模板)将从LESSON对象中获取),从而导致父组件模板被更新。这可以工作,但是角度不会处理注入的内容,innerHtml因此无法使用routerLink和其他东西。

const metadata = new ComponentMetadata({

template: this.templateString,

});

在哪里templateString传递给子组件作为子组件的Input属性。双方MetaDataComponentResolver已被弃用/去掉angular2.1.0

因此,问题不仅仅涉及动态组件的创建(如在几个相关的SO问题中所述),如果我为每个课程内容都定义了组件,问题将更容易解决。这意味着我需要为100个不同的课程预先声明100个不同的组件。不推荐使用的元数据提供的行为类似于在单个组件运行时更新模板(在路由参数更改时创建和销毁单个组件)。

因为它似乎在近角的释放,即要创建需要的所有组件/注入动态需要被预先定义entryComponents之内@NgModule。在我看来,与上述问题相关,如果我需要上100堂课(需要动态动态创建的组件),则意味着我需要预定义100个组件

基于更新1,可以通过ViewContainerRef.createComponent()以下方式完成:

// lessons.ts

@Component({ template: html string loaded from somewhere })

class LESSON_1 {}

@Component({ template: html string loaded from somewhere })

class LESSON_2 {}

// exported value to be used in entryComponents in @NgModule

export const LESSON_CONTENT_COMPONENTS = [ LESSON_1, LESSON_2 ]

现在在路由参数的父组件中更改

const key = // determine lesson name from route params

/**

* class is just buzzword for function

* find Component by name (LESSON_1 for example)

* here name is property of function (class)

*/

const dynamicComponent = _.find(LESSON_CONTENT_COMPONENTS, { name: key });

const lessonContentFactory = this.resolver.resolveComponentFactory(dynamicComponent);

this.componentRef = this.lessonContent.createComponent(lessonContentFactory);

父模板如下所示:

<div *ngIf="something" #lessonContentContainer></div>

where

lessonContentContainer装饰@ViewChildren属性,lessonContent装饰为@ViewChild,并初始化ngAfterViewInit

()为:

ngAfterViewInit () {

this.lessonContentContainer.changes.subscribe((items) => {

this.lessonContent = items.first;

this.subscription = this.activatedRoute.params.subscribe((params) => {

// logic that needs to show lessons

})

})

}

,那就是所有组件(LESSON_CONTENT_COMPONENTS)都需要预定义。有没有一种方法可以使用单个组件并在运行时更改该组件的模板(更改路由参数)?

回答:

您可以使用以下HtmlOutlet指令:

import {

Component,

Directive,

NgModule,

Input,

ViewContainerRef,

Compiler,

ComponentFactory,

ModuleWithComponentFactories,

ComponentRef,

ReflectiveInjector

} from '@angular/core';

import { RouterModule } from '@angular/router';

import { CommonModule } from '@angular/common';

export function createComponentFactory(compiler: Compiler, metadata: Component): Promise<ComponentFactory<any>> {

const cmpClass = class DynamicComponent {};

const decoratedCmp = Component(metadata)(cmpClass);

@NgModule({ imports: [CommonModule, RouterModule], declarations: [decoratedCmp] })

class DynamicHtmlModule { }

return compiler.compileModuleAndAllComponentsAsync(DynamicHtmlModule)

.then((moduleWithComponentFactory: ModuleWithComponentFactories<any>) => {

return moduleWithComponentFactory.componentFactories.find(x => x.componentType === decoratedCmp);

});

}

@Directive({ selector: 'html-outlet' })

export class HtmlOutlet {

@Input() html: string;

cmpRef: ComponentRef<any>;

constructor(private vcRef: ViewContainerRef, private compiler: Compiler) { }

ngOnChanges() {

const html = this.html;

if (!html) return;

if(this.cmpRef) {

this.cmpRef.destroy();

}

const compMetadata = new Component({

selector: 'dynamic-html',

template: this.html,

});

createComponentFactory(this.compiler, compMetadata)

.then(factory => {

const injector = ReflectiveInjector.fromResolvedProviders([], this.vcRef.parentInjector);

this.cmpRef = this.vcRef.createComponent(factory, 0, injector, []);

});

}

ngOnDestroy() {

if(this.cmpRef) {

this.cmpRef.destroy();

}

}

}

以上是 Angular 2.1.0动态动态创建子组件 的全部内容, 来源链接: utcz.com/qa/425073.html

回到顶部