在Angular 6/7中编译HTML

时间:2019-02-05 11:45:15

标签: angular

我想知道是否有可能:

  • 我有一个使用某些组件的html页面。
  • 我想动态加载此html页面,它是从资产文件夹提供的。
  • 我希望我使用的组件得到编译。

目前我正在做这样的事情:

const html = this.http.get('/assets/content/chapter1.html', { responseType: 'text' });
    html.subscribe(
      (res) => {
        this.content = this.sanitizer.bypassSecurityTrustHtml(res);
      },
      (err) => console.log(err),
      () => console.log('Complete')
    );

我的模板

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

这可能吗? 如果是,怎么办?

2 个答案:

答案 0 :(得分:0)

首先,要发布一个有效的示例非常困难,因为我拥有的有效示例是通过JSON文件生成组件的。

dynamic-page.component.ts

import { Component, Inject, AfterViewInit, NgModule, Compiler, ViewChild, ViewContainerRef, ComponentRef, OnDestroy, ViewEncapsulation } from "@angular/core";
import { AppService } from "../../shared/app.service";
import { DynamicPageService } from "./dynamic-page.service";
import { NetgaugeKpiModule } from "../../ui-components/netgauge-kpi/netgauge-kpi.module";
import { UiGridModule } from "../ui-grid/ui-grid.module";
import { LteBoxModule } from "../../ui-components/lte-box/lte-box.module";
import { Router, ActivatedRoute, RouterModule } from "@angular/router";
import { IEyesightConfig } from "../../../eyesight.config";
import { Subscription } from "rxjs";
import { CpkMonitorModule } from "../cpk-monitor/cpk-monitor.module";
import { SmallKpiBoxModule } from "../../ui-components/small-kpi-box/small-kpi-box.module";
import { IframeWrapperModule } from "../iframe-wrapper/iframe-wrapper.module";
import { LineChartModule } from "../../ui-components/charts/line-chart/line-chart.module";
import { PieChartModule } from "../../ui-components/charts/pie-chart/pie-chart.module";
import { ProgressMultiModule } from "../../ui-components/progress-multi/progress-multi.module";
import { GraphPageModule } from "../../ui-components/charts/graph-page.module";
import { DropDownsModule } from "@progress/kendo-angular-dropdowns";
import { APP_CONFIG } from "../../shared/constants";

@Component({
    selector: "dynamic-page",
    template: "<ng-container #vc></ng-container>",
    encapsulation: ViewEncapsulation.None
})
export class DynamicPageComponent implements AfterViewInit, OnDestroy {
    @ViewChild("vc", { read: ViewContainerRef }) public vc: ViewContainerRef;
    private cmpRef: ComponentRef<any>;
    private data: any[] = [];
    private pageConfig: any;
    private pageConfigName: string;
    private currentId: number = 1;

    private subscriptions: Subscription[] = [];

    constructor(
        @Inject(AppService) private readonly appService: AppService,
        @Inject(DynamicPageService) private readonly dynamicPageService: DynamicPageService,
        @Inject(Compiler) private readonly _compiler: Compiler,
        @Inject(APP_CONFIG) private readonly appConfig: IEyesightConfig,
        @Inject(ActivatedRoute) private readonly route: ActivatedRoute,
        @Inject(Router) private readonly router: Router
    ) { }

    public getAttributeValue(configKey, value, datasources: object[], id) {
        let configValue = value;
        let attributeValue: any | any[];
        const isString = _.isString(configValue);
        const angularData = isString ? _.startsWith(configValue, "{{") : false;
        if (angularData) {
            configValue = configValue.replace("{{", "");
            configValue = configValue.replace("}}", "");
        }
        const splittedValue: string[] = isString ? configValue.split(".") : [];
        const datasourceIndex = isString ? _.findIndex(datasources, (x) => x.name.match("^" + splittedValue[0])) : -1;
        const bodyData = configKey.toLowerCase() === "body";
        if (datasourceIndex !== -1) {
            const dataPath = splittedValue.slice(1).join(".");
            const data = _.get(datasources[datasourceIndex], dataPath);
            if (angularData) {
                this.data[id + configKey] = data;
                attributeValue = `{{data['${id + configKey}']}}`;

            } else if (dataPath.length === 0) {
                this.data[id + configKey] = datasources[datasourceIndex];
                attributeValue = `data['${id + configKey}']`;
            } else if (!bodyData) {
                this.data[id + configKey] = data;
                attributeValue = `data['${id + configKey}']`;
            } else {
                attributeValue = data;
            }
        } else if (!isString && splittedValue.length === 0) {
            if (_.isArray(configValue)) {
                configValue.forEach((innerConfig, innerConfigIndex) => {
                    if (!_.isString(innerConfig)) {
                        _.keys(innerConfig).forEach((innerConfigProperty) => {
                            const innerConfigKey = configKey + innerConfigIndex + innerConfigProperty + innerConfig[innerConfigProperty];
                            innerConfig[innerConfigProperty] = this.getAttributeValue(innerConfigKey, innerConfig[innerConfigProperty], datasources, id);
                            if (_.startsWith(innerConfig[innerConfigProperty], "data[")) {
                                const dataKey = innerConfig[innerConfigProperty].match(/[^']*(?='\])/)[0];
                                innerConfig[innerConfigProperty] = this.data[dataKey];
                                // console.log(
                                //     "Property: ",innerConfigProperty,
                                //     "\nInner config key: " + innerConfigKey,
                                //     "\nData key: " + dataKey,
                                //     "\n", this.data[dataKey],
                                //     "\n\n",
                                //     "\n\n");
                            }
                        });
                    }
                });
            } else {
                _.keys(configValue).forEach((innerConfig, innerConfigIndex) => {
                    const innerConfigKey = configKey + innerConfigIndex + innerConfig + configValue[innerConfig];
                    configValue[innerConfig] = this.getAttributeValue(innerConfigKey, configValue[innerConfig], datasources, id);
                    if (_.startsWith(configValue[innerConfig], "data[")) {
                        const dataKey = configValue[innerConfig].match(/[^']*(?='\])/)[0];
                        configValue[innerConfig] = this.data[dataKey];
                    }
                });
            }
            this.data[id + configKey] = configValue;
            attributeValue = `data['${id + configKey}']`;
        } else {
            attributeValue = configValue;
        }
        return attributeValue;
    }

    public generateWidgetHtml(widget): string {
        const id = this.currentId++;
        const cssClass = widget.cssClass ? `class="${widget.cssClass}"` : "";
        let attributes = "";
        let body = "";
        const datasources = widget.dataSources ? widget.dataSources : [];
        if (widget.config) {
            _.keys(widget.config).forEach((configKey: string) => {
                let camelCaseKey: string = "";
                configKey.split("-").forEach((part, index) => {
                    if (index === 0) {
                        camelCaseKey = part;
                    } else {
                        camelCaseKey += part.substr(0, 1).toUpperCase() + part.substr(1);
                    }
                });
                const bodyData = camelCaseKey.toLowerCase() === "body";
                const attributeValue = this.getAttributeValue(camelCaseKey, widget.config[configKey], datasources, id);
                if (!bodyData) {
                    attributes += `${camelCaseKey}="${attributeValue}"`;
                } else {
                    body += attributeValue;
                }
            });
        }
        if (widget.widgets) {
            widget.widgets.forEach((childWidget, childIndex) => {
                body += this.generateWidgetHtml(childWidget);
            });
        }
        const widgetHtml = `<${widget.type} ${cssClass} ${attributes}> ${body} </${widget.type}>`;

        return `${widgetHtml}`;
    }

    public buildHtmlFromPageConfig(): string {
        let html = "";
        this.pageConfig.widgets.forEach((widget, index) => {
            const widgetHtml = this.generateWidgetHtml(widget);
            html += `${widgetHtml}`;
        });
        return html;
    }

    public ngAfterViewInit() {
        const sub = this.route.params.subscribe((params) => {
            if (params.pagename && params.pagename.length > 0) {
                this.pageConfigName = params.pagename + ".page-config.json";
                this.appService.getPageConfig(this.pageConfigName).then((pageConfig) => {
                    this.dynamicPageService.getPageConfigWidgetsData(pageConfig).then((pageConfigWithData) => {
                        this.vc.clear();
                        this.cmpRef = null;

                        this.pageConfig = pageConfigWithData;
                        const htmlTemplate = this.buildHtmlFromPageConfig();

                        // tslint:disable-next-line:max-classes-per-file
                        @Component({
                            template: htmlTemplate
                        }) class DynamicComponent {
                            public data: any[];
                        }
                        // tslint:disable-next-line:max-classes-per-file
                        @NgModule({
                            imports: [
                                 //IMPORT ALL MODULES THAT WILL / SHOULD BE DYNAMICALLY CREATED
                            ],
                            declarations: [DynamicComponent] //this will be what is generating the code
                        }) class DynamicModule { }

                        const mod = this._compiler.compileModuleAndAllComponentsSync(DynamicModule);
                        const factory = mod.componentFactories.find((comp) =>
                            comp.componentType === DynamicComponent
                        );
                        this.cmpRef = this.vc.createComponent(factory);
                        this.cmpRef.instance.data = this.data;
                        this.appService.hidePageLoader();
                    }).catch((err) => {
                        // tslint:disable-next-line:no-console
                        console.log("Error loading page config data: \"" + this.pageConfigName + "\": ", err);
                        this.appService.setLoadingError({ errorMessage: "Error loading page config data: \"" + this.pageConfigName + "\"", error: err });
                    });
                }).catch((err) => {
                    // tslint:disable-next-line:no-console
                    console.log("Error loading page config: \"" + this.pageConfigName + "\": ", err);
                    // this.appService.setLoadingError({errorMessage: "Error loading page config: \"" + this.pageConfigName + "\"", error: err});
                    this.router.navigate([this.appConfig.defaultRoute]);
                });
            } else {
                this.router.navigate([this.appConfig.defaultRoute]);
            }
        });
        this.subscriptions.push(sub);
    }

    public ngOnDestroy() {
        this.subscriptions.forEach((sub) => {
            sub.unsubscribe();
        });
    }
}

app-routing.module.ts

@NgModule({
    imports: [
RouterModule.forRoot(
            [
                {path: ":pagename", component: DynamicPageComponent, canActivate: [AuthorizationGuard]},
                {path: ":pagename/:pageparam", component: DynamicPageComponent, canActivate: [AuthorizationGuard]},
                {path: "**", component: DynamicPageComponent, canActivate: [AuthorizationGuard]}
            ],
            {
                useHash: true
            }
        )
    ],
    exports: [
        RouterModule
    ]
})
export class AppRoutingModule {}

现在,创建一个名为YOUR-COMPONENT-NAME.page-config.json的JSON文件

现在,当您尝试导航到http://localhost:1337/YOUR-COMPONENT-NAME时。动态页面将被调用,它将查找具有该名称的json文件。

该文件的外观示例如下。 在此示例中,我们将生成3个组件,将一些数据输入到其@Input参数中,并且还将创建一个通用的html-div-tag并将css-class附加到其上。

{
  "widgets": [
     {
          "type": "div",
          "cssClass": "col-md-2",
          "widgets": [
            {
              "type": "YourComponentSelector",
              "config": {
                "[inputParameterNameInYourComponent]": 0,
                "characteristic-name": "w/e",
              }
            }
          ]
        },
        {
          "type": "div",
          "cssClass": "col-md-3" //just generate a generic div with a CSS-class.
        },
        {
          "type": "div",
          "cssClass": "col-md-2",
          "widgets": [
            {
              "type": "YourComponentSelector",
              "config": {
                "[inputParameterNameInYourComponent]": 0,
                "characteristic-name": "w/e",
              }
            }
          ]
        },
        {
          "type": "div",
          "cssClass": "col-md-2",
          "widgets": [
            {
              "type": "YourComponentSelector",
              "config": {
                "[inputParameterNameInYourComponent]": 0,
                "characteristic-name": "w/e",
              }
            }
          ]
        }
      ]
    }
  ]
}

在此文件中-您可以构造任何要动态创建的内容。

假设您有一个名为“ administration.component.ts”的组件。

当您现在导航到/administration时,动态页面将查找administration.page-config.json并构建包含组件和html元素的页面。

希望这至少对您有所帮助,有许多方法可以动态创建组件,这可能是一种稍微高级的方法,但是如果正确实现,它确实很有用。

答案 1 :(得分:0)

DELETE FROM npitz_reduced_tmp WHERE destinazione='UNITED STATES' AND ndc LIKE CONCAT('','%') AND ndc NOT LIKE ''   -   77