14

I'm using ngTemplateOutlet with dynamic value.

<ng-container *ngFor="let part of objectKeys(config);">
    <ng-container *ngIf="config[part]">
        <ng-container [ngTemplateOutlet]="part"></ng-container>
    </ng-container>
</ng-container>

<ng-template #one></ng-template>
<ng-template #two></ng-template>
  • Where config is an object
  • Where config[part] is a boolean
  • Where part is the key of object and the value passed to ngTemplateOutlet.

I always get the error :

ERROR TypeError: templateRef.createEmbeddedView is not a function

I've followed : https://stackoverflow.com/a/41241329/5627096

But maybe I can't do something like that.

Actually the config object contains boolean, like I said, and define the part of a form to display.

It's really big form and for better reading, I'm looking for a solution to split it.

UPDATE

config object looks like :

config = {
    one: true,
    two: false
}

So in my form only the <ng-template #one></ng-template> is displayed. If I turn two to true, both are displayed.

I don't know if it's the best approach. I can use *ngIf but with this solution I have really unreadable big code.

Swarovski
  • 581
  • 2
  • 8
  • 25

2 Answers2

23

Add these to the components class

@ViewChild('one') one:TemplateRef<any>;
@ViewChild('two') two:TemplateRef<any>;

and get the template references using

<form no-validate (ngSubmit)="onSubmit(search)">
    <ng-container *ngFor="let part of objectKeys(config);">
        <ng-container *ngIf="config[part]">
            <ng-container [ngTemplateOutlet]="this[part]"></ng-container>
        </ng-container>
    </ng-container>
</form>

StackBlitz example

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • 1
    Thank you but ngOutletContext is used to pass data inside a , right ? What I want is a reference to the . I mean if `part = one` so the `` is displayed. – Swarovski Oct 01 '17 at 15:09
  • Not sure what the problem is. Perhaps you mean `[ngTemplateOutlet]="one"` or if this doesn't work also add `@ViewChild('one') one:TemplateRef;` to your component (the same for `two`) – Günter Zöchbauer Oct 01 '17 at 15:24
  • I think you need the `@ViewChild()` code from my previous comment and use `this[config[part]]` with `*ngFor` (not sure). If you create a https://stackblitz.com/ or Plunker to reproduce, I can have a closer look. – Günter Zöchbauer Oct 01 '17 at 15:34
  • Seems the link doesn't yet contain my changes. See my updated answer until I figured the sharing feature of Stackblitz out. – Günter Zöchbauer Oct 01 '17 at 15:56
  • Some blackout of mine. Works the same as in Plunker. I need to fork, save, share. I updated the link in the question. – Günter Zöchbauer Oct 01 '17 at 16:01
  • 1
    :) Thank you Günter, I've updated your post to make it works like I want. Here the last working code : https://stackblitz.com/edit/angular-2txidk?file=app%2Fapp.component.css – Swarovski Oct 01 '17 at 16:12
  • Thanks for your attempt to improve my answer, but I think the modification doesn't do what I intended. The intention was to guard agains the `@ViewChild()` value not being available yet, instead of the config value not being available. Your change only guards agains `objectKeys(config)` not returning `null` values (if I remember your modification correctly) but I don't think this can happen. Did my version cause an error for you? – Günter Zöchbauer Oct 01 '17 at 16:46
  • No error, but it returns all templates when it should return only the requested template : `config = { one: true, two: false }` has to display only the "one" template. – Swarovski Oct 01 '17 at 16:52
  • You're right. Sorry, I misunderstood the intention of the `*ngIf`. – Günter Zöchbauer Oct 01 '17 at 17:10
  • No problem :) Thank you again for your help. – Swarovski Oct 01 '17 at 17:15
  • 1
    Spectacular. I was able to solve my problem!! https://dynamic-template-outlet.stackblitz.io – Sampgun Sep 05 '18 at 13:12
  • What does `this` in `[ngTemplateOutlet]="this[part]` mean? – tom Jan 11 '19 at 00:19
  • 1
    @tom its the `this` of the component class as in `this.one` where `one` is the `@ViewChild('one') one:TemplateRef` – galki Jan 11 '19 at 00:37
0
  • Render template refs by passing dynamic values to ngTemplateOutlet Directive
  • use Attribute binding to pass reference of templateRef stored in templateRefs array

.ts file

export class RenderTemplateRefsInNgTemplateOutletDirective {
  @ViewChild('one', { static: false }) one:TemplateRef<any>;
  @ViewChild('two', { static: false }) two:TemplateRef<any>;
  @ViewChild('three', { static: false }) three:TemplateRef<any>;

  templateRefs: Array<TemplateRef<any>> = [];

  config: any = {
    'one': true,
    'two': false,
    'three': true,
  }

  objectKeys = Object.keys;

 ngAfterViewInit() {
  const values = Object.keys(this.config).filter(key => this.config[key]);
  values.forEach(key =>{
    this.templateRefs.push(this[key]); // accessing **this** component ViewChild 
                                      // with same **name** defined as `key` in forEach
  })
 }
}

.html

<ng-container *ngFor="let template of templateRefs">
    <ng-container [ngTemplateOutlet]="template"></ng-container>
 </ng-container>
 
 <ng-template #one>
 <h1>Hello One</h1>
 </ng-template>
 
 <ng-template #two>
   <h1>Hello Two</h1>
 </ng-template>
 
 <ng-template #three>
   <h1>Hello Three</h1>
 </ng-template>

khizer
  • 1,242
  • 15
  • 13