Определить конкретный Angular TemplateRef из QueryList - PullRequest
0 голосов
/ 20 октября 2018

В Angular 6/7 у меня есть компонент, в который я проецирую контент, например так ( ParentComponent template):

<my-component [templateNames]="['t1', 't2']">
  <ng-template name="t1">...</ng-template>
  <ng-template name="t2">...</ng-template>
  <ng-template>...</ng-template> <!-- not included in [templateNames] -->
</my-component>

В классе MyComponent я могуполучить QueryList всех шаблонов с использованием декоратора ContentChildren :

@ContentChildren(TemplateRef) templates: QueryList<TemplateRef<any>>;

Сложность заключается в том, что я хочу выполнить код на определенных шаблонах, определенных с помощью ParentComponent устанавливается через @Input() templateNames.

processTemplates() {
  for (const name of this.templateNames) {
    const templateRef = this.getTemplateByName(name);
    this.doWork(templateRef);
  }
}

getTemplateByName(name) {
  const templates = this.templates.toArray();

  return templates.find(t => ?); // what can I query to distinguish templates?
}

Проблема в том, что я не знаю, как читать атрибут name или что-либо еще, что я установил в ng-шаблоне тег в ParentComponent .Я понятия не имею, как отличить один TemplateRef от другого;

Имейте в виду, что MyComponent не может делать никаких предположений относительно того, какие имена будут использоваться, или все ng-templates должен быть обработан - последний в моем примере выше не должен обрабатываться, потому что он не указан в @ Input () templateNames .Могу ли я установить в ParentComponent что-нибудь, что поможет мне различить два TemplateRef ?

1 Ответ

0 голосов
/ 20 октября 2018

Вы можете выбрать один из следующих методов:

Если он доступен только для 2 компонентов, вы можете получить к ним доступ с помощью методов получения QueryList (первый и последний)

@ContentChildren(TemplateRef) templates: QueryList<TemplateRef<any>>;

ngAfterContentInit() {
    console.log(this.templates.first);    // Gives you the 1st template child
    console.log(this.templates.last);     // Last template child (2nd child)     
}

Поиск по индексу

this.templates.find((template, index) => index == 1); // 2nd template child

Другая альтернатива

Создал Stackblitz Демо , используярасширение для Компонентов

1.) Создайте TemplateContentComponent Это послужит вашим ChildComponent и добавит @Input ()

    @Component({
      selector: 'template-content',
      template: `
          // If no ng-template reference available, show its ng-content
          <ng-content *ngIf="!template"></ng-content>

         // Else, show the ng-template through ng-container
         <ng-container *ngIf="template"
                       [ngTemplateOutlet]="template"></ng-container>
      ` 
    })
    export class TemplateContentComponent {
        @Input() name: string;    // Serves as your component id
    }

2.) Создать TemplateContainerComponent - это будет служить ParentComponent

 @Component({
  selector: 'template-container',
  template: `<ng-content></ng-content>`
})
export class TemplateContainerComponent implements AfterContentInit  {

    @ContentChildren(TemplateContentComponent) templates: QueryList<TemplateRef<any>>;

      ngAfterContentInit() {
        // You can now check whether you'll be fetching a template
        // based on the names you want provided from parent template.

        const t1 = this.templates.find((template: any) => template.name === 't1');

        console.log(t1);   // This will show the t1 component
                           // which t1 and t2 are the same component
                           // but had set a name @Input() as their ID
      }

    }

Result

3.) Вкл.Ваш AppComponent Шаблон

<template-container>
  // Can be a raw template, good for ng-content
  <template-content [name]="'t1'">t1 template</template-content>

  // Or a template from ng-template, good for ng-container
  <template-content [name]="'t2'"
                    [template]="userList"></template-content>
</template-container>


// User List Template
<ng-template #userList>
  <h1>User List</h1>
</ng-template>

Template

...