Получить ng-содержимое ng-template из компонента в другой компонент

Я знаю, что есть и другие идеи, но я хочу использовать декораторы ng-template, ng-content и @ContenChild() указанным ниже способом. Идея этого возникла, когда мы увидели реальное воплощение угловатых компонентов материала.

Здесь у меня есть два компонента:

  1. Компонент контейнера (приложение-контейнер)
  2. Дочерний компонент (приложение-потомок)

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

У меня есть связанное решение: https://stackblitz.com/edit/ngtemplateoutlet-and-content-projection?file=src%2Fapp%2Fapp.component.html. Но это не совсем соответствует моим требованиям.

Желателен следующий html, в основном в app.component.html:

<app-container>
   <app-nav>
       <a routerLink="/home">Home</a>
       <a routerLink="/about">About</a>
   </app-nav>
  <app-main>
    <p>This is the content to be reflect.</p>
  </app-main>
</app-container>

Что должно привести к следующему выводу:

<div class="container">
        <nav role="navigation" class="navigation">
             <a routerLink="/home">Home</a>
             <a routerLink="/about">About</a>
        </nav>
        <section role="main" class="main__content">
               <p>This is the content to be reflect.</p>
        </section>
</div>

Мои коды выглядят так

import { Component, ContentChild, AfterContentInit } from '@angular/core';

@Component({
    selector: 'app-main'
    template: `<ng-template><ng-content></ng-content></ng-template>`
})
export class AppMain {

}
@Component({
    selector: 'app-nav'
    template: `<ng-template><ng-content></ng-content></ng-template>`
})
export class AppNav {

}


@Component({
    selector: 'app-container',
    template: `
               <div class="container">
                      <nav role="navigation" class="navigation">
                         <ng-container [ngTemplateOutlet="nav"></ng-container>
                      </nav>
                      <section role="main" class="main__content">
                         <ng-container [ngTemplateOutlet]="main"></ng-container>
                      </section>
               </div>
              `
})
export class AppContainer implements AfterContentInit {
    @ContentChild(AppMain) main: AppMain;
    @ContentChild(AppNav) nav: AppNav;

    ngAfterContentInit() {       
        console.log(this.main);
        console.log(this.nav);
    }
}



person bhawanishiv    schedule 29.04.2020    source источник
comment
Есть ли конкретная причина не использовать выбираемый ng-content вместо ng-container[ngTemplateOutlet] внутри app-container? Я думаю, это более интуитивно понятно ... но, конечно, это может быть дело вкуса.   -  person julianobrasil    schedule 30.04.2020


Ответы (2)


демонстрация Stackblitz

Я думаю, вы получите более чистую структуру, если не будете использовать ngTemplateOutlet. ИМО, вам даже не нужен элемент ng-template. Конечно, я не знаю вашей конечной цели, но вы могли бы сделать то, что я показываю ниже, что очень похоже на то, что у вас есть, но я думаю, что выбираемые ng-content в app-container делают общую структуру более интуитивной и более простой для понимания дерева компонентов. настройка хотя:

@Component({
  selector: "app-main",
  template: `<ng-content></ng-content>`
})

export class AppMain {}
@Component({
  selector: "app-nav",
  template: `<ng-content></ng-content>`
})
export class AppNav {}

@Component({
  selector: "app-container",
  template: `
    <div class="container">
      <nav role="navigation" class="navigation">
        <ng-content select="[nav-slot]"></ng-content>
      </nav>
      <section role="main" class="main__content">
        <ng-content select="[main-slot]"></ng-content>
      </section>
    </div>
  `
})
export class AppContainer {
  @ContentChild(AppMain) main: AppMain;
  @ContentChild(AppNav) nav: AppNav;

  ngAfterContentInit() { /* ... */}
}

И вы можете использовать это так:

<app-container>
    <app-nav nav-slot>
        <a routerLink="/home">Home</a>
        <a routerLink="/about">About</a>
    </app-nav>
    <app-main main-slot>
        <p>This is the content to be reflect.</p>
    </app-main>
</app-container>
person julianobrasil    schedule 29.04.2020

Я нашел решение !!

Собственно, чтобы получить содержимое любого компонента, мы можем использовать декоратор @ViewChild(). Итак, для компонентов app-nav и app-main я использовал ту же технику, которая показана ниже:

import { Component, ContentChild, AfterContentInit, TemplateRef, ViewChild } from '@angular/core';
@Component({
    selector: 'app-main',
    template: `<ng-template><ng-content></ng-content></ng-template>`
})
export class AppMain{
    @ViewChild(TemplateRef, { static: true }) content: TemplateRef<any>;
}
@Component({
    selector: 'app-nav',
    template: `<ng-template><ng-content></ng-content></ng-template>`
})
export class AppNar {
    @ViewChild(TemplateRef, { static: true }) content: TemplateRef<any>;

}


@Component({
    selector: 'app-container',
    template: `
               <div class="container">
                      <nav role="navigation" class="navigation">
                         <ng-container [ngTemplateOutlet="nav.content"></ng-container>
                      </nav>
                      <section role="main" class="main__content">
                         <ng-container [ngTemplateOutlet]="main.content"></ng-container>
                      </section>
               </div>
              `
})
export class AppContainer implements AfterContentInit {

    @ContentChild(AppMain) main: AppMain;
    @ContentChild(AppNav) nav!: AppNav;

    ngAfterContentInit() {

    }

}

Итак, в app.component.html у меня было:

<app-container>
   <app-nav>
       <a routerLink="/home">Home</a>
       <a routerLink="/about">About</a>
   </app-nav>
  <app-main>
    <p>This is the content to be reflect.</p>
  </app-main>
</app-container>

И результат, который я получил, действительно является желаемым:

<div class="container">
        <nav role="navigation" class="navigation">
             <a routerLink="/home">Home</a>
             <a routerLink="/about">About</a>
        </nav>
        <section role="main" class="main__content">
               <p>This is the content to be reflect.</p>
        </section>
</div>
person bhawanishiv    schedule 30.04.2020