2

[Step1] I have an object "article" which has an array of multiple content elements. Depending on the type of the element (eg. header/image), a different template should be shown. I don't want to explicitly have an own component for this, if not necessary, so I'm guessing whether ViewChild nor ContentChild is needed?

I have looked into all of the ngTemplate related questions, but havent found a solution yet. I tried to rewrite https://stackblitz.com/edit/angular-q1y2vz from ngTemplateOutlet with dynamic value, but failed so far.

component.ts

articles: any[] = [ {
    "id_seq": "1234",
    "content":[
      {
        "id": "123456",
        "order": 0,
        "type": "header",
        "data":
          {
            "text": "loremipsum"
          }
      },
      {
        "id": "234567",
        "order": 1,
        "type": "image",
        "data":
          {
            "url": "http://www.google.de/image.jpg"
          }
      }]
  }]

component.html

<ng-container *ngFor="let content of articles[0]?.content;">
  <ng-container [ngTemplateOutlet]="content?.type">
  </ng-container>
</ng-container>


<ng-template #header >
  <p>I'm a header</p>
</ng-template>

<ng-template #image >
  <p>I'm an image</p>
</ng-template>

Depending on syntax and code placement of ngTemplateOutlet, I get an error

templateRef.createEmbeddedView is not a function

or nothing is rendered at all.

If i type a static string like "header", it works. So I'm guessing, the content?.type is not the way to go. On the other hand, something like this works fine:

<accordion>
  <accordion-group heading="articlecontent" [isOpen]="isFirstOpen">
    <div class="accordion_no_side_margin">
      <accordion-group *ngFor="let content of articles[0]?.content"
                       [heading]="content?.type">
        {{ content?.id }}
        {{ content?.order }}
        {{ content?.type }}
        {{ content?.data }}
      </accordion-group>
    </div>
  </accordion-group>
</accordion>

[Step2] Ultimately I do want to merge both code snippets, so that the ng-template should be executed inside the accordion.

[Step3] Later I intend to add ngTemplateOutletContext and provide some information, but the other steps should work just fine without that.

At the moment I'm using @angular-devkit/core 8.1.3

connectedMind
  • 421
  • 4
  • 17

2 Answers2

2

Since it just did not wanted to work with ngFor for whatever reason, i tried ngSwitchCase, which works good enough and never looked behind since then (although it would have been nice to have the templates/ng-containers on the outside)

<ng-container *ngFor="let content of localArticles[0]?.content">
  <ng-container [ngSwitch]="content?.type">

    <ng-container *ngSwitchCase="'header'">
      <p>I'm a header</p>
    </ng-container>

    <ng-container *ngSwitchCase="'image'">
      <p>I'm an image</p>
    </ng-container>

  </ng-container>
</ng-container>
connectedMind
  • 421
  • 4
  • 17
0

Dont know what is about with articles[0]?.content in your code but try like that:

<ng-container *ngFor="let content of articles[0]?.content;">
    <ng-container *ngIf="content?.type == header; then header; else image"></ng-container>
    <ng-template #header >
      <p>I'm a header</p>
    </ng-template>

    <ng-template #image >
      <p>I'm an image</p>
    </ng-template>
  </ng-container>

try like this if above not work Your array are not loading:

<div *ngIf="articles | async as artic">
  <ng-container *ngFor="let article of artic">
    <ng-container *ngfor="let ar of article.content">

      <ng-container *ngIf="ar.type == header; then header; else image"></ng-container>
      <ng-template #header>
        <p>I'm a header</p>
      </ng-template>

      <ng-template #image>
        <p>I'm an image</p>
      </ng-template>
    </ng-container>
  </ng-container>
</div>

If You have hard coded array You can remove | async pipe.

Answear to what You told me in coments:

<div *ngIf="articles | async as artic">
  <ng-container *ngFor="let article of artic">
    <ng-container *ngfor="let ar of article.content">

      <ng-container *ngIf="ar.type == 'header'"><p>I'm a header</p></ng-container>
      <ng-container *ngIf="ar.type == 'image'"><p>I'm a header</p></ng-container>
      <ng-container *ngIf="ar.type == 'pain in ass'"><p>I'm a header</p></ng-container>
      <ng-container *ngIf="ar.type == 'love masturbating'"><p>I'm a header</p></ng-container>
      <ng-container *ngIf="ar.type == 'love dogs'"><p>I'm a header</p></ng-container>

    </ng-container>
  </ng-container>
</div>
Mises
  • 4,251
  • 2
  • 19
  • 32
  • Interesting approach, haven't seen this yet. But doesn't work unfortunately. articles[0]?.content is just a workaround, because i don't have an article model defined yet and there is just one article in a local array. – connectedMind Oct 02 '19 at 10:20
  • I see what you did there (at least partly). The thing is, i have 10+ types (header & image are just examplatory), so using if/else is not really an option. Also what's the point of using ngFor 2 times...? – connectedMind Oct 02 '19 at 11:18
  • Becouse You have array in array ? Thats the point of 2x ngFor. – Mises Oct 02 '19 at 12:04
  • If You have 10+ types just use `*ngIf` for each one type. Like `*ngIf="type == header"` next one `*ngIf="type == image"` etc. – Mises Oct 02 '19 at 12:07