Load Dynamic templates within a single component using Angular 4 Load Dynamic templates within a single component using Angular 4 angular angular

Load Dynamic templates within a single component using Angular 4


I know this question is old, but hopefully this helps people who are attempting similar things.

The unfortunate thing about what you want is that the easiest way to do it is to simply make each template its own component. Otherwise, you have to inject and sanitize HTML. They removed ng-include and similar capabilities because of security risks of injecting un-sanitized HTML. Its wouldn't be that much of a P.I.T.A if you didn't have to specifically import and declare all those additional components in your module, but alas...

You can create a simple directive that will get templateRefs, and then query elements on your page that have those directives, get the template ref from it, and insert them elsewhere. This would at least let you keep all the templates in a separate file. I usually put 3 or 4 templates in a separate component and include them in the component that wants to render them with . I'll describe how to do that.

Directive to get template refs

import { Directive, TemplateRef, Input } from '@angular/core';@Directive({ selector: 'get-template',})export class GetTemplateDirective {  @Input() name: string;  constructor(public template: TemplateRef<any>) {  }}

Then for the templates, create a super simple component that has them all

@Component({  selector: 'sub-component-templates',  template: `<ng-template get-template [name]="tpl1">  Put Whatever here, including other components if you please</ng-template> <ng-template get-template [name]="tpl2">  Different template here</ng-template>  ... and so on and so on...`})export class Templates { }

Import all the relevant new components into your module, then include them inside your main component that will render the templates

I usually do it with ng-content so its clear in the parent component that this component is referencing another one for its templates.

For example, in the parent..

<sub-component>    <sub-component-templates></sub-component-templates></sub-component>

Then in the sub component

 import { Component, ViewChild, ContentChildren, QueryList } from '@angular/core';import { GetTemplateDirective } from 'wherever';@Component({selector: 'sub-component',template: `<ng-content></ng-content> <div #templateRenderer></div>`})export class SubComponent {@ViewChild('templateRenderer',{read:ViewContainerRef}) anchor: ViewContainerRef;@ContentChildren(GetTemplateDirective) templates: QueryList<GetTemplateDirective>;ngAfterContentInit()  {  ... at this stage, you will have access to all the included templates with that directive on them. You can perform your logic to choose which one you want. Once you have selected the proper one, you can embed it like so ...  let desiredTemplateName = 'whatever';     for (let t of this.templates.toArray()) {       if(t.name === desiredTemplateName) {          this.anchor.createEmbeddedView(t.template);          break;               }      }     }}

You can see that this is ridiculously complicated for what you are trying to do. It would be easier to just create them as separate components, and use the ngSwitchCase to choose the proper one. The advantage to the method I've described above is that it lets you keep your templates wherever you want really, and you could include 100 in the same external component (which is really no more than the bare minimum decorated component with a template) if you wanted, or move them around with a service, or whatever.

See here for a working example of how to use the compiler - https://plnkr.co/edit/fdP9Oc?p=info

Still quite complicated...

If you store the template as a property of the class, you could change it later as needed. Just add a template ref import...

 import { Component, ViewChild, ContentChildren, QueryList, TemplateRef } from '@angular/core';

and then create a property

 template: TemplateRef<any>;

Then later you could switch it out with one from your querylist and create the embeddedview again using the view container's methods.

Angular 2 / 4 made certain things easier... and made certain things waaaaaay more difficult. But I guess in this case, its in the name of security.


I'm actually trying to figure this out as we speak and when I came across the answer above it gave me an idea that I'm about to try. Hopefully I'll have some success with it and be able to update this answer with something more concrete.

I'm always working on my questionnaires and I have questions that are multiple choice questions with worded answers, multiple choice questions with a "scale of 1-10" type of mechanism, then some questions that require a text answer.

I think making a component and wrapping each template in an ngIf condition that connects to a variable in the class which the data will be passed into can trigger the templeate.

So the data can look something like this

Questions:[{    question:'blahblahblah',    answers: [..array of answers..],    template: 'a'    },    {    question: 'yaddayaddayadda',    answers: [],    template: 'b'    },    {    etc.    }    ]

Then in the component class you can have something like this

@Component ({    selector: 'question-component',    templateUrl: './template.html'})export class QuestionComponent {    @input() data: yourDataType;    constructor() {} }

then in the template for this component have something like

<div *ngIf="data.template === a">    <!-- code for template with binding and everything --></div><div *ngIf="data.template === b">    <!-- code --></div><!-- etc. etc. etc. -->

Then in the main component's template you can do something like

<div *ngFor = "question of Questions">    <question-component [data]="question"></question-component></div>

This is all hypothetical off the top of my head so I may be missing some things but I feel it's worth it to have here as something to start poking around at in the meantime. I'm going to see if I can get it to work for my needs.