Angular: добавить динамически созданный компонент как дочерний элемент целевого элемента

Я реализую директиву для добавления действий в ячейку mat-таблицы:

<ng-container matColumnDef = "actions">
  <mat-header-cell *matHeaderCellDef></mat-header-cell>
  <mat-cell
    *matCellDef = "let row"
    tableActions
    [editAction] = "true"
    [actionInputData] = "actionInputData"
    [row] = "row"
  >
  </mat-cell>
</ng-container>

tableActions — это директива. Моя цель — добавить действия как дочерний элемент mat-cell.

Я уже пробовал много способов и много искал, но не нашел способа сделать это таким образом, чтобы все работало так, как ожидалось:

  1. Я использовал _viewContainerRef для создания и добавления действия, но действие всегда добавляется рядом с мат-ячейкой, а не как дочерний элемент.

    пусть компонентRef: ComponentRef = this._viewContainerRef.createComponent(компонент);

  1. Я использовал рендерер Angular (Renderer2). Сработало добавление компонента как дочернего элемента mat-cell, но mat-icon, mat-tooltip и стандартные директивы Angular, такие как *ngIf, не работают. Похоже, что все директивы, добавленные в html действия, не работают.

Здесь я создал компонентComponentRef с помощью функции createComponent ядра Angular и добавил его к целевому элементу (mat-cell).

  let componentRef: ComponentRef<any> = createComponent(component, {
    environmentInjector: this._appRef.injector,
  }); 

  this._renderer.appendChild(
    this._elementRef.nativeElement as HTMLElement,
    componentRef.location.nativeElement
  );

HTML-код действия редактирования:

<button
  mat-icon-button
  (click) = "editRow(row)"
  color = "primary"
  matTooltip = "{{ 'edit' | translate }}"
>
  <mat-icon color = "primary">edit</mat-icon>
</button>

Мой последний вопрос: как я могу добавить эти компоненты действий таким образом, чтобы все работало так, как если бы я реализовал их непосредственно в ячейке mat?

Пожалуйста, поделитесь стекблицем минимальной проблемы с проблемой, воспроизведенной для отладки!

Naren Murali 21.03.2024 10:14

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

Stefan 21.03.2024 10:42

Вы правы, не нужен, моя ошибка!

Naren Murali 21.03.2024 11:10
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Angular и React для вашего проекта веб-разработки?
Angular и React для вашего проекта веб-разработки?
Когда дело доходит до веб-разработки, выбор правильного front-end фреймворка имеет решающее значение. Angular и React - два самых популярных...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
Мое недавнее углубление в Angular
Мое недавнее углубление в Angular
Недавно я провел некоторое время, изучая фреймворк Angular, и я хотел поделиться своим опытом со всеми вами. Как человек, который любит глубоко...
Освоение Observables и Subjects в Rxjs:
Освоение Observables и Subjects в Rxjs:
Давайте начнем с основ и постепенно перейдем к более продвинутым концепциям в RxJS в Angular
1
3
85
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

У меня это начало работать, выполнив следующие шаги:

  1. Обеспечение добавления импорта (CommonModule, MatIconModule, MatButtonModule) к компоненту, который будет отображаться динамически.

  2. Использование метода setInput для создания привязки, необходимой для компонента angular, иначе привязка не будет работать для @Input.

  3. Запуск обнаружения изменений дочернего компонента, чтобы изменения компонента были обнаружены, с помощью componentRef.changeDetectorRef.detectChanges();

визуализированный компонент

import { CommonModule } from '@angular/common';
import { Component, Input } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';

@Component({
  selector: 'app-table-action-container',
  standalone: true,
  imports: [CommonModule, MatIconModule, MatButtonModule],
  template: `
  <button mat-button color = "primary" *ngIf = "show">
    asdf
    <mat-icon color = "primary"></mat-icon>
  </button>
  <button mat-button color = "primary" *ngIf = "!show">
    qwer
    <mat-icon color = "primary"></mat-icon>
  </button>
  `,
  styleUrl: './table-action-container.component.scss',
})
export class TableActionContainerComponent {
  @Input() show = false;
}

директива

import {
  ApplicationRef,
  ComponentRef,
  Directive,
  ElementRef,
  Input,
  Renderer2,
  createComponent,
} from '@angular/core';
import { TableActionContainerComponent } from './table-action-container/table-action-container.component';

@Directive({
  selector: '[appTableActions]',
  standalone: true,
})
export class TableActionsDirective {
  @Input() show = false;
  constructor(
    private _appRef: ApplicationRef,
    private _renderer: Renderer2,
    private _elementRef: ElementRef
  ) {}

  ngOnInit() {
    const component = TableActionContainerComponent;
    let componentRef: ComponentRef<any> = createComponent(component, {
      environmentInjector: this._appRef.injector,
    });
    componentRef.setInput('show', this.show);

    this._renderer.appendChild(
      this._elementRef.nativeElement as HTMLElement,
      componentRef.location.nativeElement
    );
    componentRef.changeDetectorRef.detectChanges();
  }
}

HTML-фрагмент

  ...
  <ng-container matColumnDef = "symbol">
    <th mat-header-cell *matHeaderCellDef>Action</th>
    <td
      mat-cell
      *matCellDef = "let element;let index = index"
      appTableActions
      [show] = "index % 2 === 0"
    ></td>
  </ng-container>
  ...

Демо-версия Stackblitz

Всплывающая подсказка по-прежнему не работает. Я просто навел указатель мыши на элемент, чтобы вызвать всплывающую подсказку, и теперь метка не отображается. Я использую mat-tooltip в качестве директивы ( matTooltip = "{{ 'edit' | Translate }}" ). Есть ли у вас идеи, почему ярлык не отображается?

Stefan 22.03.2024 07:31

@Stefan Вы добавили модуль MatTooltipModule в дочерний компонент?

Naren Murali 22.03.2024 07:32

Я использую общий модуль, который импортирует и экспортирует MatTooltipModule. Если я реализую действия напрямую, это работает. Но если я использую Renderer2 для добавления его в DOM, это не сработает.

Stefan 22.03.2024 07:34

@Stefan, пожалуйста, поделитесь стекблицем с воспроизведенной проблемой, если возможно, новым вопросом, поскольку это новая проблема!

Naren Murali 22.03.2024 07:50

Другие вопросы по теме