angular8 доступ к содержимому ng-шаблона, созданного с помощью ngTemplateOutlet - PullRequest
0 голосов
/ 10 апреля 2020

Я работаю с динамическим c контентом и использую ngTemplateOutlet с пользовательской директивой для его создания, но теперь Мне нужен доступ к созданным элементам контента . Я не смог найти подходящих ответов о моей проблеме в списке похожих вопросов.

Моя текущая настройка (я опущу ненужные части, чтобы сделать пример как можно более понятным)

Компонент хоста контента:

(grid.host.component.ts)
@ContentChildren(VvsGridInputCellDirective, { descendants: false }) public inputCols: QueryList<VvsGridInputCellDirective<T>>;

public getTemplateElement(): HTMLElement {
     // checks for undefined and null
     return this.inputCols.first().templateRef.elementRef;
}

значительная часть шаблона компонента хоста:

(host.template.html)
<td *ngFor="let col of visibleColumns" [class.resized-col]="col?.width > 0">
    <div class="cell-height-wrapper" [style.width]="col?.width > 0 ? col.width+'mm':'auto'">
        <ng-template [ngTemplateOutlet]="col.templateRef" [ngTemplateOutletContext]="{$implicit: data}" ></ng-template>
    </div>
</td>

this.getTemplateElement() возвращает elementRef из ng-template (что просто некоторые комментарии), ну, потому что ng-template не существует в DOM. Мне нужно получить содержимое этой директивы ng-template, но я не знаю, как;

Это директива, которая передает шаблон для ngTemplateOutlet:

(host.cell.directive.ts)
@Directive({
    selector: "ng-template[appVvsGridInputCell]",
    exportAs: "appVvsGridInputCell"
})
export class VvsGridInputCellDirective<T> {

public definition: ColumnDefinition<T>;
public model: T;

constructor(public templateRef: TemplateRef<any>) {
    this.definition = new ColumnDefinition();
}

И, наконец, использование директивы. Это контент, к которому я хочу получить доступ:

(uses.all.above.component.template.html)
<ng-template appVvsGridInputCell #cell="appVvsGridInputCell" let-data header="COMMENT">
    <div class="no-padding">
        <input class="form-control" type="text" [(ngModel)]="data.comment">
    </div>
</ng-template>

Так что это все, что нужно (кроме большого количества беспорядка). Пожалуйста, дайте мне знать, как я могу получить доступ к элементу, который был определен в ng-template appVvsGridInputCell, потому что я хочу управлять им в host.component. Также оставьте записку, если вам нужны какие-либо разъяснения.

Я просмотрел много вопросов, но это те, которые я не закрывал:

Stackblitz

Я создал проект концепции стекаблица, который повторяет мою проблему: https://stackblitz.com/edit/angular-nx8gyx

1 Ответ

1 голос
/ 17 апреля 2020

Вы не можете получить элементы содержимого шаблона из TemplateRef. Ссылка на шаблон - это просто ссылка на шаблон, а не на отображаемый шаблон. Он представлен как узел комментария в HTML DOM, как вы нашли, и не имеет никакого отношения к контенту.

Я думаю, для вашего случая решение состоит в том, чтобы определить другую директиву, которая применяется к элементам ввода внутри шаблоны. Таким образом, вы можете легко запрашивать также все элементы ввода, используя другой запрос @ContentChildren.

Например, такая директива может выглядеть следующим образом:

@Directive({
    selector: '[appVvsTemplateInput]'
})
export class VvsTemplateInputDirective {
  @Input('appVvsTemplateInput') inputCell: VvsGridInputCellDirective;

  constructor(public inputElementRef: ElementRef) {
  }
}

Я добавил свойство inputCell так что вы можете позже сопоставить ввод с правильной ячейкой. Вот пример шаблона столбца, использующего также эту директиву:

<ng-template appVvsGridInputCell #cell3="appVvsGridInputCell" let-data header="COMMENT">
  <div class="regular-padding">
    <input [appVvsTemplateInput]="cell3" type="text" [(ngModel)]="data.comment">
  </div>
</ng-template>

Теперь в компонент сетки вы добавляете запрос @ContentChildren для этой директивы, и вы получите все входные данные с этой директивой. Из них вы можете найти тот, который соответствует столбцу, который вы ищете.

Вот соответствующий код из компонента:

@ContentChildren(VvsTemplateInputDirective) private columnInputs: QueryList<VvsTemplateInputDirective>;

public getTemplateInputElement(): HTMLElement {
  const foundColumn = this.columnInputs.toArray().find((templateInputDirective) => templateInputDirective.inputCell === this._visibleInputCols[1]);
  return foundColumn.inputElementRef.nativeElement;
}

Есть другое решение, которое является более хакерским решением с моей точки зрения. Вы можете использовать запрос @ViewChildren, чтобы получить все элементы, которые являются выходами шаблона. Это снова элементы комментариев. Из этих элементов комментария вы можете получить основной элемент содержимого шаблона, получив nextSibling из nativeElement. Angular присоединяет динамическое содержимое c в качестве родственного элемента контейнера. Я думаю, что немного опасно полагаться на это. Также вам нужно будет сделать более прямой обход DOM, чтобы найти элемент ввода.

Чтобы упростить запрос, полезно добавить имя к элементу с помощью директивы ngTemplateOutlet.

<ng-container #templateOutlet
    [ngTemplateOutlet]="col.templateRef" 
    [ngTemplateOutletContext]="{$implicit: inputRow}" >
</ng-container>

Затем вы можете выполнить запрос по имени в компоненте и получить элемент содержимого в виде nextSibling.

@ViewChildren('templateOutlet') private templateOutlets: QueryList<ElementRef>;

public getTemplateContentElement(): HTMLElement {
  return this.templateOutlets.toArray()[1].nativeElement.nextSibling;
}

. Здесь также есть ссылка на форк вашего StackBlitz * 1034. * где я добавил оба этих подхода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...