【问题标题】:Angular dynamic component loading角度动态组件加载
【发布时间】:2017-07-19 12:32:55
【问题描述】:

我正在学习 Angular,我有一个带有返回页面内容的 API 的 CMS。页面可以有表单的短代码,我更新了 API 以用组件选择器替换短代码

示例页面内容如下所示

<div>bla bla bla </div>
<app-form [id]="1"></app-form>

在 Angular 中,我创建了 FormComponent 来相应地加载表单,但是当我使用上述选择器获取页面内容时,我得到了错误

'app-form' 不是已知元素:.....

我做了一些研究,发现我需要一些动态组件加载器,但根据我的场景找不到任何工作示例,任何人都可以帮助我解决这个问题

【问题讨论】:

    标签: angular angular-components


    【解决方案1】:

    确实,您必须动态创建这些组件。有关执行此操作的示例代码,请参见此 plunkr:https://plnkr.co/edit/kkM1aR4yPcIqeBhamoDW?p=info

    虽然你需要一个 ViewContainer 来让 Angular 知道在哪里插入动态组件。这不起作用,因为您无法绑定到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(/&quot;/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 都可编辑。

    【讨论】:

      猜你喜欢
      • 2022-01-04
      • 2017-10-10
      • 1970-01-01
      • 2019-07-11
      • 2019-07-15
      • 2017-11-02
      • 1970-01-01
      • 2019-02-08
      • 2018-05-29
      相关资源
      最近更新 更多