【发布时间】:2017-02-24 21:49:08
【问题描述】:
我在angular 2.1.0 中尝试做的是动态创建子组件,这些子组件应该被注入到父组件中。例如父组件是lessonDetails,其中包含所有课程的共享内容,例如Go to previous lesson、Go 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 对象中获取)导致父组件模板被更新。这可行,但 Angular 不会处理通过 innerHtml 注入的内容,因此无法使用 routerLink 和其他东西。
在新的角度发布之前,我使用http://blog.lacolaco.net/post/dynamic-component-creation-in-angular-2/ 的解决方案解决了这个问题,我一直使用ComponentMetadata 和ComponentResolver 来动态创建子组件,例如:
const metadata = new ComponentMetadata({
template: this.templateString,
});
其中templateString 被传递给子组件作为Input 属性传递给子组件。 MetaData 和 ComponentResolver 在 angular 2.1.0 中已弃用/删除。
所以问题不仅仅是关于动态组件的创建,就像在一些相关的 SO 问题中描述的那样,如果我为每个课程内容定义了组件,问题将更容易解决。这意味着我需要为 100 个不同的课程预先声明 100 个不同的组件。已弃用的元数据提供的行为类似于在单个组件的运行时更新模板(在路由参数更改时创建和销毁单个组件)。
更新 1: 在最近的 Angular 版本中,所有需要动态创建/注入的组件都需要在 entryComponents 中的 @NgModule 中进行预定义。所以在我看来,与上述问题相关,如果我需要 100 个课程(需要动态创建的组件),这意味着我需要预定义 100 个组件
更新2:在更新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>
其中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)都需要预定义。
有没有办法使用单个组件并更改该组件的模板在运行时(路由参数更改)?
【问题讨论】:
-
见hl7.org/fhir/StructureDefinition/…。添加 HTML 只是添加 HTML,如果您想要动态组件,您可以使用
ViewContainerRef.createComponent()。否则,只会为静态添加到组件模板的选择器创建组件和指令。 -
@GünterZöchbauer 感谢您的回复,实际上我正在使用
ViewContainerRef.createComponent()请检查有问题的更新 2 部分 -
您不能在运行时修改组件的模板。有一些方法可以在运行时创建新组件。我不知道这方面的细节,但在 SO 上有类似问题的答案。
标签: javascript angular