Angular 2/4 component with dynamic template or templateUrl

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.

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


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.

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/webpack and :

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 :

skipCodeGeneration. Optional, defaults to false. Disable code generation and do not refactor the code to bootstrap. This replaces templateUrl: "string" with 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 :

ts-loader

The rule for ts will look like this :

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

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

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

See Issue