【问题标题】:Angular 2/4 component with dynamic template or templateUrl带有动态模板或 templateUrl 的 Angular 2/4 组件
【发布时间】:2018-01-04 17:00:11
【问题描述】:

我一直在尝试到处寻找解决方案。

我有一个具有不同“皮肤”的项目,它们基本上是不同的模板/Css 集。

我正在尝试让我的组件使用基于变量 THEME_DIR 的皮肤。

不幸的是,我找不到如何实现这一点。我在 angular.io 上查看了Dynamic Component Loader,但没有成功。

我也在这里看了一些答案,也没有成功。

有人有想法吗?

这是我迄今为止尝试过的:

import { ComponentFactoryResolver, ViewContainerRef } from '@angular/core';

// @Component({
//     templateUrl: '../../assets/theme/'+THEME_DIR+'/login.template.html',
// })

export class LoginComponent implements, AfterViewInit {


    private log = Log.create('LoginPage');

    constructor(private mzksLsRequestService: MzkLsRequestService,
                private componentFactoryResolver: ComponentFactoryResolver,
                public viewContainerRef: ViewContainerRef) {
    }



    ngAfterViewInit() {
        let componentFactory = this.componentFactoryResolver.resolveComponentFactory(new Component({
            templateUrl: '../../assets/theme/default/login.template.html',
        }));
        let viewContainerRef = this.viewContainerRef;
        viewContainerRef.clear();
        let componentRef = viewContainerRef.createComponent(componentFactory);

    }

}

【问题讨论】:

    标签: angular typescript themes


    【解决方案1】:

    你可以这样做:

    import {
      Compiler, Component, Injector, VERSION, ViewChild, NgModule, NgModuleRef,
      ViewContainerRef
    } from '@angular/core';
    
    
    @Component({
      selector: 'my-app',
      template: `
          <h1>Hello {{name}}</h1>
          <ng-container #vc></ng-container>
      `
    })
    export class AppComponent {
      @ViewChild('vc', {read: ViewContainerRef}) vc;
      name = `Angular! v${VERSION.full}`;
    
      constructor(private _compiler: Compiler,
                  private _injector: Injector,
                  private _m: NgModuleRef<any>) {
      }
    
      ngAfterViewInit() {
        const tmpCmp = Component({
            moduleId: module.id, templateUrl: './e.component.html'})(class {
        });
        const tmpModule = NgModule({declarations: [tmpCmp]})(class {
        });
    
        this._compiler.compileModuleAndAllComponentsAsync(tmpModule)
          .then((factories) => {
            const f = factories.componentFactories[0];
            const cmpRef = f.create(this._injector, [], null, this._m);
            cmpRef.instance.name = 'dynamic';
            this.vc.insert(cmpRef.hostView);
          })
      }
    }
    

    只要确保 URL 正确且模板已加载到客户端即可。

    阅读Here is what you need to know about dynamic components in Angular了解更多详情。

    【讨论】:

    • 非常感谢。我想现在我的问题是 webpack 在编译模板时抱怨......我需要找到解决方法......
    • 刚刚尝试了全新的 Angular cli 项目,它在 webpack 上运行良好。您使用什么构建过程?
    • 我使用离子样板。当我将变量放在模板路径中时它会抱怨(请参阅我的代码中的 THEME_DIR),因为它似乎找不到正确的路径
    • 我明白了,不幸的是我对此并不熟悉。我认为您应该创建另一个问题,因为它与我回答的问题并不真正相关
    • 如果有帮助,您也可以接受或投票赞成这个答案,谢谢
    【解决方案2】:

    我在尝试从服务器加载动态模板时遇到问题(我想进行安全检查,在提供 html 之前在服务器端进行翻译。

    我在更改 webpack 配置后解决了这个问题。事实上,在完成ng eject 之后,它创建了一个webpack.config.js,其中包含一个.ts 加载器@ngtools/webpack 和:

    new AotPlugin({
      "mainPath": "main.ts",
      "replaceExport": false,
      "hostReplacementPaths": {
        "environments\\environment.ts": "environments\\environment.ts"
      },
      "exclude": [],
      "tsConfigPath": "src/main/front/tsconfig.app.json",
      "skipCodeGeneration": true
    })
    

    最后一个,是问题的根源。它涉及 AOT(提前)。根据文档: ngtools 在选项部分,它被提及:

    跳过代码生成。可选,默认为 false。禁用代码 生成并且不要重构代码以引导。 这将 templateUrl: "string" 替换为 template: require("string")

    如果您不希望您的 templateUrl 被 AOT 编译,我建议您删除 AotPlugin,并使用 ts-loader 而不是 @ngtools/webpack 参见:

    ts-loader

    ts 的规则如下所示:

    {
        test: /\.tsx?$/,
        loader: 'ts-loader'
    }
    

    现在您可以根据需要从相对 URL 加载新模板。示例:

    @Component({
        selector : "custom-component",
        templateUrl : "/my_custom_url_on_server"
    })
    export class CustomComponent {
    }
    

    Issue

    【讨论】:

    • ng 弹出不再受支持。而且我不推荐这种解决方案。这个想法是让 Angular 编译模板
    【解决方案3】:

    从 Ivy(我认为)开始,我们可以在 templateUrl 中使用静态变量(例如环境)。 例如:

        import { environment } from 'src/environments/environment';
        @Component({
            selector: 'home',
            templateUrl: `./skins/${environment.skin}/home.page.html`,
            styleUrls: ['./skins/${environment.skin}/home.page.scss']
        })
    

    【讨论】:

    • 是的,这在编译时很酷,但是运行时呢?
    猜你喜欢
    • 2016-02-18
    • 1970-01-01
    • 1970-01-01
    • 2017-10-18
    • 1970-01-01
    • 2017-12-20
    • 2016-04-23
    • 2017-11-20
    相关资源
    最近更新 更多