Angular 8: как использовать слот Multi-Content-Projection / Multiple-Transclusion дважды?

  • У меня есть проект Angular 8.2 с двумя разными режимами отображения (пейзаж | портрет)
  • И в каждом из них есть панель инструментов вверху и внизу, окружающая основной контент.
  • В menu а также основные contentзависит от модуля, поэтому я использую слоты. Другими словами: один из 5 различных возможных родительских компонентов использует этот компонент и предоставляетmain содержание и (индивидуально разные) menu, используя угловую проекцию контента.
    <ng-template #menu><ng-content select="[slot='menu']"></ng-content></ng-template>
    <ng-template #content><ng-content select="[slot='content']"></ng-content></ng-template>

    <section *ngIf="landscape">
        <div class="global-ui-top">
            <ng-container *ngTemplateOutlet="menu"></ng-container> // 1st
        </div>
        <some-main-content>
            <ng-container *ngTemplateOutlet="content"></ng-container>
        </some-main-content>
        <div class="global-ui-bottom">
            <ng-container *ngTemplateOutlet="menu"></ng-container> // 2nd
        </div>
    </section>

    // portrait mode
    <section *ngIf="!landscape">
        ... pretty similar to above, also 2× menu, 1× content...

Проблема: как я могу использовать слот дважды?** Ошибка не возникает, если я использую, например..

A <ng-container *ngTemplateOutlet="menu"></ng-container> A
B <ng-container *ngTemplateOutlet="menu"></ng-container> B

... однако слот "выбирается один раз" в последний раз (тег между двумя буквами A остается пустым). Другими словами, мой 1-й.global-ui-top остается пустым.

nb: Этоng-detourв строке 1+2 помогает обойти определенную ошибку. Это не причиняет вреда, но и не помогает (к сожалению,ng-template-содержание не замораживается после "первого заполнения"). Видимо, в отношении слотов существует принцип "уникальности в выборе".

Есть ли способ вставить содержимое слота меню в шаблон любого типа и повторно использовать его несколько раз (все видимые одновременно)?**

  • возможно причудливый флаг на любом <ng-content> или <ng-template? ("статический"?!?)
  • или сначала каким-то образом сбить содержимое слота в @viewChild() (в component.ts)...
  • еще...?

незначительное обновление

Кажется возможным захватить ссылку ng-template в View Child:

   @ViewChild('menu', {static: true}) menuA: TemplateRef<any>;

... а console.dir() показывает мне действительный ElementRef, но мне не удается вывести его в.html-шаблоне, т.е. <ng-template [ngTemplateOutlet]="menuA"></ng-template>

1 ответ

Решение

Может быть, этот доклад будет полезным.

Насколько я понимаю, ng-contentэто не создает контент, он просто перемещает содержимое из одной части в другую.

Я думаю, решение вашей проблемы - использовать ng-template. Например:

projected.component.ts

let instances = 0;

@Component({
  selector: 'app-projected',
template: `projected instance nr: {{ instanceId }}`
})
export class ProjectedComponent implements OnInit {
  instanceId: number;

  constructor() { }

  ngOnInit() {
    this.instanceId = ++instances;
  }

}

parent.component.ts

@Component({
  selector: 'app-parent',
  template: `
    <h3>Parent component</h3>

    <p>Using content #1</p>
    <ng-container *ngTemplateOutlet="content"></ng-container>

    <p>Using content #2</p>
    <ng-container *ngTemplateOutlet="content"></ng-container>
  `,
})
export class ParentComponent implements OnInit {
  @ContentChild('content', { read: TemplateRef }) content: TemplateRef<any>;

  constructor() { }

  ngOnInit() {
  }

}

И вот что важно:

<app-parent>
  <ng-template #content>
    <app-projected></app-projected>
  </ng-template>
</app-parent>

Насколько я понимаю, что внутри ng-templateможно рассматривать как план. Поэтому каждый раз, когда вы используетеng-template, вы создадите новый экземпляр этого чертежа.

Демо

Другие вопросы по тегам