Я пытаюсь создать компонент с множественным выбором, который может принимать шаблон для каждого элемента опции выбора. В основном это работает, шаблоны берутся из ng-content в компоненте option и отображаются в штрафе «выберите всплывающее окно».
У меня возникают проблемы при попытке отобразить выбранный параметр в компоненте выбора. Кажется, что шаблон может отображаться только в одном месте за раз, поэтому, когда выбранный параметр отображается в списке выбора, он удаляется из всплывающего окна.
Есть ли способ клонировать компонент TemplateRef? На самом деле я не возражаю, если контекст не обновляется для шаблона, поскольку в настоящее время я ничего из него не использую, только шаблон.
Включив несколько фрагментов кода ниже для ясности, я думаю, что это нормально.
Использование в somepage.component.html
:
<my-select [(value)] = "vals">
<my-option *ngFor = "let x of [1,2,3]" [value] = "x">Option {{x}}</my-option>
</my-select>`
my-select.component.html
...
<ng-container [ngTemplateOutlet] = "getSelectedOptionTemplate()"></ng-container>
...
my-select.component.ts
getSelectedOptionTemplate(){
// Some way to clone here could solve the issue?
return this.getSelectedOption().template;
}
my-select-overlay.component.html
...
<ng-container *ngFor = "let opt of options;">
<ng-container [ngTemplateOutlet] = "getTemplate(opt)"></ng-container>
</ng-container>
...
my-option.component.html
<ng-template>
<ng-content></ng-content>
</ng-template>
my-option.component.ts
...
@ViewChild(TemplateRef)
template: TemplateRef<any>;
...
Я нашел на Github решение этой проблемы.
Кажется, что использование того же TemplateRef
работает, когда ng-template
оборачивает компонент, который содержит ng-content
.
Представьте, что нам нужно получить что-то вроде:
<ng-template>
<my-option>
... option content ...(<ng-content></ng-content>)
</my-option>
</ng-template>`
Чтобы получить структуру выше, мы можем реализовать структурная директива. Из документов:
Angular transforms the asterisk in front of a structural directive into an
<ng-template>
that surrounds the host element and its descendants.
Код для структурной директивы будет:
@Directive({
selector: "[appOptionTemplate]"
})
export class OptionTemplateDirective {
@Input("appOptionTemplate")
value: any;
constructor(
public templateRef: TemplateRef<any>
) {}
}
(обратите внимание на следующее:
templateRef
в конструкторInput
)При заполнении параметров выбора мы будем использовать следующее:
<app-select>
<ng-container *ngFor = "let x of [1,2,3]; let i=index;">
<app-option *appOptionTemplate = "x">
Option {{x}}
</app-option>
</ng-container>
</app-select>
Теперь мы будем использовать структурную директиву для запроса содержимого в компоненте select
:
@ContentChildren(OptionTemplateDirective)
options: QueryList<OptionTemplateDirective>;
А для отображения опции мы будем использовать:
<ng-container *ngTemplateOutlet = "option.templateRef"></ng-container>
Пример:https://stackblitz.com/edit/angular-ivy-pues8t
Github тема:
https://github.com/angular/angular/issues/37995
Подробнее о структурных директивах: