带有动态模板或 templateUrl 的 Angular 2/4 组件

Posted

技术标签:

【中文标题】带有动态模板或 templateUrl 的 Angular 2/4 组件【英文标题】:Angular 2/4 component with dynamic template or templateUrl 【发布时间】: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);

    


【问题讨论】:

【参考方案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']
    )

【讨论】:

是的,这在编译时很酷,但是运行时呢?

以上是关于带有动态模板或 templateUrl 的 Angular 2/4 组件的主要内容,如果未能解决你的问题,请参考以下文章

无法在 Angularjs 中使用 templateUrl 加载模板

在模板中呈现动态变化的组件

Angular.js 组件动态模板URL

Ionic 3 动态模板 URL

ionic 向路由中的templateUrl(模板页)传值

动态指令:templateUrl