我想要做的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
和其他东西。
在新的 angular 发布之前,我使用http://blog.lacolaco.net/post/dynamic-component-creation-in-angular-2/ 中的解决方案解决了这个问题,我一直在使用ComponentMetadata
withComponentResolver
来动态创建子组件, 喜欢:
const metadata = new ComponentMetadata({
template: this.templateString,
});
WheretemplateString
作为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)都需要预定义。
有没有办法使用单个组件并在运行时更改该组件的模板(在路由参数更改时)?