Как отрендерить вложенный ng-шаблон

У меня такая вложенная структура ng-template.

@Component({
  selector: 'my-app',
  template: `
    <list>
      <ng-template *ngFor="let item of Items" #ListItem>
        <ng-template #ListItemLine>{{ item[0] }}</ng-template>
        <ng-template #ListItemLine>{{ item[1] }}</ng-template>
        <ng-template #ListItemLine>{{ item[2] }}</ng-template>
        I can see this line, but can't get above templates
      </ng-template>
    </list>
  `,
})
export class App {
  Items: Array<Array<string>> = [
    [ "1-1", "1-2", "1-3", ],
    [ "2-1", "2-2", "2-3", ],
    [ "3-1", "3-2", "3-3", ],
    [ "4-1", "4-2", "4-3", ],
    [ "5-1", "5-2", "5-3", ],
  ]
}

Как я могу визуализировать детей ng-component в моем компоненте:

@Component({
  selector: 'list',
  template: `
    <ul>
      <li *ngFor="let item of Items">
        <ng-container *ngTemplateOutlet="item"></ng-container>
      </li>
    </ul>
  `,
})
export class ListComponent {

  @ContentChildren('ListItem') public Items;

}

Plunkr https://plnkr.co/edit/Hi1ZqPAAYyIbclUuzRrl?p=preview

Заранее спасибо.

Обновить

В конце я хочу обернуть компоненты Angular Material в свои компоненты, поэтому, если я найду более лучший пользовательский интерфейс, чем материал, мне не придется менять все гарантии компонентов материала в моей программе, мне просто нужно будет изменить реализацию моего компоненты пользовательского интерфейса оболочки.

Например, попробуем обернуть mat-list компонент. Мне нужно сделать обертку для mat-list контейнера, назовем его my-list:

@Component({
  selector: 'my-list',
  template: `
    <mat-list>
      <ng-content></ng-content>
    </mat-list>
  `,
})

и обертка для mat-list-item:

@Component({
  selector: 'my-list-item',
  template: `
    <mat-list-item>
      <ng-content></ng-content>
    </mat-list>
  `,
})

Результатом рендеринга HTML будет:

  • my-list
    • mat-list
      • my-list-item
        • mat-list-item
      • ...

Каждый компонент материала окружен моей оболочкой, поэтому директивы и стили, поставляемые с материалом, не будут работать.


person Vladimir    schedule 20.11.2017    source источник
comment
Я не думаю, что вам действительно нужен вложенный шаблон. Не могли бы вы подробнее объяснить, чего пытаетесь достичь?   -  person AlesD    schedule 21.11.2017
comment
В вашем коде отображается только родительский шаблон, потому что вы выбираете только родительские шаблоны. @ContentChildren ('ListItem') выбирает только шаблоны верхнего уровня, поэтому отображаются только они. Чтобы отобразить также дочерние шаблоны, вы должны что-то с ними сделать. Возможно, вам следует просто использовать обычный * ngfor для расширения вложенных объектов внутри родительского шаблона и избегать вложенных шаблонов.   -  person AlesD    schedule 21.11.2017
comment
@AlesD ng-template дает мне возможность визуализировать его содержимое без элемента оболочки, поэтому вложенная структура ng-template должна дать мне возможность визуализировать дерево элементов без оболочки. В конце я хочу инкапсулировать компонент списка материалов внутри моего компонента и иметь возможность использовать такие директивы, как matLine, которые не работают, если они завернуты.   -  person Vladimir    schedule 21.11.2017
comment
@AlesD Да, я знаю, что не обрабатываю их, потому что не знаю, как на них ссылаться.   -  person Vladimir    schedule 21.11.2017
comment
Если вы хотите ссылаться на них из другого шаблона, вам нужно сделать это в коде, я все же думаю, что есть лучшее решение из того, что вы хотите сделать. Если вы хотите построить рекурсивную древовидную структуру, вы можете создать рекурсивный компонент.   -  person AlesD    schedule 21.11.2017
comment
Вот часть того, как отрендерить все из вашего шаблона. Это также более эффективно, поскольку вы не создаете новые подшаблоны для каждого рендеринга родительского шаблона. ссылка   -  person AlesD    schedule 21.11.2017
comment
@AlesD Пожалуйста, проверьте мое обновление.   -  person Vladimir    schedule 21.11.2017
comment
Хорошо, спасибо, теперь это более понятно. Приму решение и выложу.   -  person AlesD    schedule 21.11.2017


Ответы (1)


Вот как я бы решил эту проблему на основе предоставленной вами информации. Как вы уже предположили, я сделал два компонента list и list-item. Компонент списка отображает компоненты list-item на основе входного массива, и содержимое компонента списка должно содержать шаблон, определяющий шаблон элемента списка. Образец кода:

    @Component({
      selector: 'list',
      template: `
        <ul>
          <list-item *ngFor="let item of items" [data]="item" [itemTemplate]="itemTemplate"></list-item>
          <ng-content></ng-content>
        </ul>
      `,
    })
    export class ListComponent {
      @ContentChild(TemplateRef)
      public itemTemplate: TemplateRef;
      @Input()
      public items: any[];

    }

Затем компонент list-item просто отображает шаблон элемента списка, предоставленный в элементе контейнера. Образец кода:

@Component({
  selector: 'list-item',
  template: `
      <li>
        <ng-container *ngTemplateOutlet="itemTemplate; itemContext"></ng-container>
      </li>
  `,
})
export class ListItemComponent {
  @Input()
  public data: any;
  @Input()
  public itemTemplate: Template;
  public get itemContext(): any {
    return { $implicit: data };
  }
}

Затем вы можете использовать его по-разному. Я привел в пример простой список, а в другом - шаблон элемента, который снова является списком, поэтому вы получаете список списков, аналогичный дереву. Образец кода:

@Component({
  selector: 'my-app',
  template: `
    <list [items]="Items">
      <ng-template let-items>{{ items | json }}</ng-template>
    </list>
    <list [items]="Items">
      <ng-template let-items>
        <list [items]="items">
          <ng-template let-items>{{ items | json }}</ng-template>
        </list>
      </ng-template>
    </list>
  `,
})
export class App {
  Items: Array<Array<string>> = [
    [ "1-1", "1-2", "1-3", ],
    [ "2-1", "2-2", "2-3", ],
    [ "3-1", "3-2", "3-3", ],
    [ "4-1", "4-2", "4-3", ],
    [ "5-1", "5-2", "5-3", ],
  ]
}

Я также сделал образец плункера с кодом, в котором вы можете его запустить. Образец Plunker

person AlesD    schedule 21.11.2017
comment
Спасибо за вашу помощь, но я не ожидал этого. Похоже, ng-template и ng-container возможностей недостаточно для моей цели. Ваш пример передает данные через входы, и я ожидаю, что все данные будут переданы через контент. Во всяком случае, ваш пример очень полезен. Я найду обходной путь и, возможно, позже сделаю несколько пользовательских шаблонов. - person Vladimir; 23.11.2017