Как передать шаблон вложенному компоненту в Angular - PullRequest
0 голосов
/ 01 апреля 2020

Я строю автозаполнение в NativeScript и Angular (этот вопрос также относится к чистым Angular).

Разметка выглядит следующим образом:

<StackLayout>
<TextField #keywords [hint]="options?.hint" [(ngModel)]="occupation"
    (textChange)="keywordsInputChange$.next(keywords.text)">
</TextField>
<ng-container *ngTemplateOutlet="parentTemplate"></ng-container>

<ScrollView orientation="vertical" height="200" *ngIf="dataItems?.length > 0" class="m-r-16 m-l-16 search-view">
    <ListView [items]="dataItems" (itemTap)="onItemTap($event)">
        <ng-template let-item="item">
            ...
        </ng-template>
    </ListView>
</ScrollView>

и он будет использоваться извне:

<px-lookup (selected)="onOccupationSelected($event)" [options]="occupationLookupOptions">
    <ng-template let-item>
         <StackLayout class="search-item" backgroundColor="red">
               <Label [text]="item.text"></Label>
         </StackLayout>
    </ng-template>
</px-lookup>

Как вы видите, я хотел бы передать пользовательский шаблон для моего поиска, который будет использоваться ListView. Я извлекаю этот шаблон как этот

@ContentChild(TemplateRef, { static: false }) parentTemplate: TemplateRef<any>;

Я могу без проблем отобразить его в поиске, определив

<ng-container *ngTemplateOutlet="parentTemplate; context: { $implicit: item }"></ng-container>

Однако, когда я пытаюсь поместить его в LietView, который также требует шаблон я не могу заставить его работать. Я получаю сообщения об ошибках типа 'Ошибка: в шаблоне списка не найдено подходящих просмотров! Уровень вложенности: 0 ' любой элемент отображается так же, как [объект]

Я пробовал следующие варианты:

<ListView [items]="dataItems" (itemTap)="onItemTap($event)">
        1. Option ===> <ng-container *ngTemplateOutlet="parentTemplate"></ng-container> -->

        2. Option ===><ng-content></ng-content>

        3. Option ===> <ng-template let-item="item"> (top template that is required by ListView)
            <ng-container *ngTemplateOutlet="parentTemplate; context: { $implicit: item }"></ng-container> (Tried to render another template with current one by passing item down the pipe)
        </ng-template>
    </ListView>

Кто-нибудь знает, как я могу достичь этого?

Спасибо

1 Ответ

0 голосов
/ 01 апреля 2020

Ключ заключается в создании директивы для сохранения ссылки на шаблон путем использования внедрения зависимостей в TemplateRef.

Сначала директива:

// my-template.directive.ts

@Directive({ selector: '[myTemplate]' })
export class MyTemplateDirective  {
  @Input('myTemplate') type: string;

  constructor(public template: TemplateRef<any>) {}
}

(Обратите внимание, что, хотя свойство type не используется в этом простом случае, с несколькими вложенными шаблонами это будет необходимо)

После того, как в компоненте автозаполнения вы ищите дочерний элемент содержимого с этой директивой, например:

// autocomplete.component.ts

@ContentChild(MyTemplateDirective, { static: false }) set setTemplate(value: MyTemplateDirective) {
   // for multiple templates you could implement logic using value.type

   // for example:
   // this.parentTemplates[value.type] = value.template

   this.parentTemplate = value.template;
};

и в шаблоне

// autocomplete.component.html
// Basically your Option 3

<ListView [items]="dataItems" (itemTap)="onItemTap($event)">   
  <ng-template let-item="item">
     <ng-container *ngTemplateOutlet="parentTemplate; context: { $implicit: item }"></ng-container>
  </ng-template>
</ListView>

тогда вы будете использовать его так:

<px-lookup (selected)="onOccupationSelected($event)" [options]="occupationLookupOptions">
    <ng-template let-item myTemplate="pxLookupElem">
         <StackLayout class="search-item" backgroundColor="red">
               <Label [text]="item.text"></Label>
         </StackLayout>
    </ng-template>
</px-lookup>
...