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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/45376628/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 04:46:31  来源:igfitidea点击:

Angular 2/4 component with dynamic template or templateUrl

angulartypescriptthemes

提问by millerf

I have been trying to find a solution for this everywhere.

我一直试图在任何地方找到解决方案。

I have a project with different 'skins', which are basically different sets of templates/Css.

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

I am trying to have my components use the skin based on a variable THEME_DIR.

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

Unfortunately, I cannot find how to make that happens. I looked into the Dynamic Component Loaderon angular.io without success.

不幸的是,我找不到如何做到这一点。我在 angular.io 上查看了动态组件加载器,但没有成功。

I also looked at a few answers here without success either.

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

Does anyone have an idea?

有没有人有想法?

This is what I tried so far:

这是我到目前为止尝试过的:

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);

    }

}

回答by Max Koretskyi

You can do it like this:

你可以这样做:

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);
      })
  }
}

Just make sure that the URL is correct and the template is loaded into the client.

只需确保 URL 正确并且模板已加载到客户端。

Read Here is what you need to know about dynamic components in Angularfor more details.

阅读这里是您需要了解的有关 Angular 中的动态组件的更多详细信息。

回答by Yacine

I had the problem when trying to load dynamicaly templates from the server (i wanted to make security check, translation on server side before serving html.

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

I've solved it after changing webpack config. In fact, after doing ng eject, it created a webpack.config.js which contains a .ts loader @ngtools/webpackand :

我在更改 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
})

This last one, is the origin of the problem. It concerns the AOT (Ahead Of Time). According to the documentation : ngtools on the options section, it's mentionned :

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

skipCodeGeneration. Optional, defaults to false. Disable code generation and do not refactor the code to bootstrap. This replaces templateUrl: "string" with template: require("string")

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

If you dont want your templateUrl to be compiled AOT, i recommand you to remove the AotPlugin, and to use of the ts-loader instead of @ngtools/webpack see :

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

ts-loader

ts-loader

The rule for ts will look like this :

ts 的规则如下所示:

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

Now you can load fresh templates from a relative URL on demand. Example :

现在,您可以按需从相对 URL 加载新模板。例子 :

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

See Issue

问题