Angular 动态组件加载
Angular dynamic component loading
我正在学习 Angular,我有一个 CMS API returns 页面内容。页面可以有表单的短代码,我更新了 API 以用组件选择器
替换短代码
示例页面内容如下所示
<div>bla bla bla </div>
<app-form [id]="1"></app-form>
在 angular 中,我创建了 FormComponent 以相应地加载表单,但是当我使用上述选择器获取页面内容时,出现错误
'app-form' 不是已知元素:.....
我做了一些研究,发现我需要一些动态组件加载器,但找不到符合我的情况的任何工作示例,任何人都可以帮助我解决这个问题
确实,您必须动态创建这些组件。请参阅此 plunkr 以获取执行此操作的示例代码:https://plnkr.co/edit/kkM1aR4yPcIqeBhamoDW?p=info
虽然您需要 Angular 的 ViewContainer 才能知道在何处插入该动态组件。这是行不通的,因为您不能绑定到 innerHTML
然后手动更改 innerHTML
的代码。我不确定,但我认为这会干扰角度变化检测。
几个月前我不得不这样做并想出了一个解决方案。我想在这一点上提一下,我不确定现在是否有更好的解决方案来解决这个问题。无论如何,我所做的不是创建动态组件,而是使用 *ngIfs 创建一些自定义渲染。
让我解释一下:您的内容包含标签。您决定这些标签的外观。
在我的例子中,我有一个标签,用户可以在他想要的任何地方插入:[galerie="key_of_gallery"]
。
所以内容可能看起来像
some normal text
<h2>Oh what a nice heading</h2>
[galerie="summer_gallery"]
text again
现在我该如何渲染它?
我必须得到类似
的东西
<div>
some normal text
<h2>Oh what a nice heading</h2>
</div>
<galerie [key]="summer_gallery"></galerie>
<div>
text again
</div>
所以我创建了一个自定义组件来创建这个:
import { Component, Input } from '@angular/core';
@Component({
selector: 'ffam-render-key-value',
template: `<div *ngFor="let contentToRender of contentArray">
<div *ngIf="contentToRender.type==='normal'" [innerHTML]="contentToRender.value">
</div>
<galerie *ngIf="contentToRender.type==='gallery'" [key]="contentToRender.key"></galerie>
</div>`
})
export class NoeRenderKeyValueComponent{
@Input('contentArray') contentArray: any[] = [];
}
该组件只需要一个标签数组,这些标签将使用 *ngFor 呈现。根据标签的类型,创建普通 HTML 或组件。
这个组件可以像
一样插入
<ffam-render-key-value [contentArray]="keyValues['_text'].arrayWithCustomTags">
</ffam-render-key-value>
为了获得这个标签数组,我创建了一个具有以下功能的服务:
public getArrayWithCustomTags(keyValue): any[] {
let arrayWithCustomTags: any[] = [];
//check if custom Tag exists in the innerHTML
if (keyValue.value.indexOf('[galerie=') !== -1) {
//replace double quotes
keyValue.value = keyValue.value.replace(/"/g, '"');
//it exists, get array of all tags
//regex that matches all [galerie="SOME KEY"] or [someAttribute="some text here"] -> You have to change this regex to fit all your tags
let pattern = /(?:(\[galerie=\"[^\"]+\"\]))+/;
//split with regexp to get array
let arrayOfContents: string[] = keyValue.value.split(new RegExp(pattern, 'gi'));
for (let i = 0; i < arrayOfContents.length; i++) {
if (typeof arrayOfContents[i] === "undefined") {
arrayOfContents.splice(i, 1);
i--;
}
else {
let customTagToBeInserted: any = {};
if (arrayOfContents[i].indexOf('[galerie=') !== -1) {
//custom tag gallery
customTagToBeInserted.type = "gallery";
//get key only
customTagToBeInserted.key = arrayOfContents[i].replace("[galerie=\"", "").replace("\"]", "");
}
//else if some other attribute or even create a switch () {}
else {
//insert the normalHtml sanitized
customTagToBeInserted.type = "normal";
customTagToBeInserted.value = this.sanitizer.bypassSecurityTrustHtml(arrayOfContents[i]);
}
arrayWithCustomTags.push(customTagToBeInserted);
}
}
}
else {
arrayWithCustomTags.push({ type: "normal", value: this.sanitizer.bypassSecurityTrustHtml(keyValue.value)});
}
return arrayWithCustomTags;
}
这将创建一个数组,如:
[0]: {type: "normal", value:"SecureHTML"},
[1]: {type: "gallery", key:"summer_gallery"},
[2]: {type: "normal", value:"SecureHTML"},
好吧,我想你明白了。
如果您创建一个带有更多标签的完整 CMS,我建议您创建一个函数,该函数可以轻松地为标签创建整个过程(正则表达式等)。
此示例代码仅适用于一个标签。
结果是组件呈现在用户放置它们的位置。
希望对你有帮助。
顺便说一句,如果您有可编辑的用户键值对,您可能会发现这很有用:https://github.com/bergben/ng2-ck-editable。这是我构建的一个小模块,可以使用 ck-editor 编辑任何 div。
我正在学习 Angular,我有一个 CMS API returns 页面内容。页面可以有表单的短代码,我更新了 API 以用组件选择器
替换短代码示例页面内容如下所示
<div>bla bla bla </div>
<app-form [id]="1"></app-form>
在 angular 中,我创建了 FormComponent 以相应地加载表单,但是当我使用上述选择器获取页面内容时,出现错误
'app-form' 不是已知元素:.....
我做了一些研究,发现我需要一些动态组件加载器,但找不到符合我的情况的任何工作示例,任何人都可以帮助我解决这个问题
确实,您必须动态创建这些组件。请参阅此 plunkr 以获取执行此操作的示例代码:https://plnkr.co/edit/kkM1aR4yPcIqeBhamoDW?p=info
虽然您需要 Angular 的 ViewContainer 才能知道在何处插入该动态组件。这是行不通的,因为您不能绑定到 innerHTML
然后手动更改 innerHTML
的代码。我不确定,但我认为这会干扰角度变化检测。
几个月前我不得不这样做并想出了一个解决方案。我想在这一点上提一下,我不确定现在是否有更好的解决方案来解决这个问题。无论如何,我所做的不是创建动态组件,而是使用 *ngIfs 创建一些自定义渲染。
让我解释一下:您的内容包含标签。您决定这些标签的外观。
在我的例子中,我有一个标签,用户可以在他想要的任何地方插入:[galerie="key_of_gallery"]
。
所以内容可能看起来像
some normal text
<h2>Oh what a nice heading</h2>
[galerie="summer_gallery"]
text again
现在我该如何渲染它? 我必须得到类似
的东西 <div>
some normal text
<h2>Oh what a nice heading</h2>
</div>
<galerie [key]="summer_gallery"></galerie>
<div>
text again
</div>
所以我创建了一个自定义组件来创建这个:
import { Component, Input } from '@angular/core';
@Component({
selector: 'ffam-render-key-value',
template: `<div *ngFor="let contentToRender of contentArray">
<div *ngIf="contentToRender.type==='normal'" [innerHTML]="contentToRender.value">
</div>
<galerie *ngIf="contentToRender.type==='gallery'" [key]="contentToRender.key"></galerie>
</div>`
})
export class NoeRenderKeyValueComponent{
@Input('contentArray') contentArray: any[] = [];
}
该组件只需要一个标签数组,这些标签将使用 *ngFor 呈现。根据标签的类型,创建普通 HTML 或组件。
这个组件可以像
一样插入 <ffam-render-key-value [contentArray]="keyValues['_text'].arrayWithCustomTags">
</ffam-render-key-value>
为了获得这个标签数组,我创建了一个具有以下功能的服务:
public getArrayWithCustomTags(keyValue): any[] {
let arrayWithCustomTags: any[] = [];
//check if custom Tag exists in the innerHTML
if (keyValue.value.indexOf('[galerie=') !== -1) {
//replace double quotes
keyValue.value = keyValue.value.replace(/"/g, '"');
//it exists, get array of all tags
//regex that matches all [galerie="SOME KEY"] or [someAttribute="some text here"] -> You have to change this regex to fit all your tags
let pattern = /(?:(\[galerie=\"[^\"]+\"\]))+/;
//split with regexp to get array
let arrayOfContents: string[] = keyValue.value.split(new RegExp(pattern, 'gi'));
for (let i = 0; i < arrayOfContents.length; i++) {
if (typeof arrayOfContents[i] === "undefined") {
arrayOfContents.splice(i, 1);
i--;
}
else {
let customTagToBeInserted: any = {};
if (arrayOfContents[i].indexOf('[galerie=') !== -1) {
//custom tag gallery
customTagToBeInserted.type = "gallery";
//get key only
customTagToBeInserted.key = arrayOfContents[i].replace("[galerie=\"", "").replace("\"]", "");
}
//else if some other attribute or even create a switch () {}
else {
//insert the normalHtml sanitized
customTagToBeInserted.type = "normal";
customTagToBeInserted.value = this.sanitizer.bypassSecurityTrustHtml(arrayOfContents[i]);
}
arrayWithCustomTags.push(customTagToBeInserted);
}
}
}
else {
arrayWithCustomTags.push({ type: "normal", value: this.sanitizer.bypassSecurityTrustHtml(keyValue.value)});
}
return arrayWithCustomTags;
}
这将创建一个数组,如:
[0]: {type: "normal", value:"SecureHTML"},
[1]: {type: "gallery", key:"summer_gallery"},
[2]: {type: "normal", value:"SecureHTML"},
好吧,我想你明白了。 如果您创建一个带有更多标签的完整 CMS,我建议您创建一个函数,该函数可以轻松地为标签创建整个过程(正则表达式等)。 此示例代码仅适用于一个标签。
结果是组件呈现在用户放置它们的位置。 希望对你有帮助。
顺便说一句,如果您有可编辑的用户键值对,您可能会发现这很有用:https://github.com/bergben/ng2-ck-editable。这是我构建的一个小模块,可以使用 ck-editor 编辑任何 div。