I'm implementing a directive to add actions to a mat-table's mat-cell:
<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 is the directive. My goal ist to append the actions as a child of mat-cell.
I've already tried lots of ways and I've searched a lot but haven't found any way to do that in a way, that all works as expected:
I used the _viewContainerRef to create and append the action but the action is alaways added next to the mat-cell and not as a child.
let componentRef: ComponentRef = this._viewContainerRef.createComponent(component);
Here I created the componentRef with the angular core's createComponent-function and appended it to the target-Element (mat-cell)
let componentRef: ComponentRef<any> = createComponent(component, {
environmentInjector: this._appRef.injector,
});
this._renderer.appendChild(
this._elementRef.nativeElement as HTMLElement,
componentRef.location.nativeElement
);
The edit action's html is:
<button
mat-icon-button
(click)="editRow(row)"
color="primary"
matTooltip="{{ 'edit' | translate }}"
>
<mat-icon color="primary">edit</mat-icon>
</button>
My final question is: How can I append these action-components in a way that all is working as I would implement them directly into the mat-cell?
It started working for me, by doing the below steps,
Ensuring the imports are added (CommonModule, MatIconModule, MatButtonModule
) to the component that is going to be rendered dynamically
Using the setInput
method to create the binding needed for the angular component, else binding will not work for @Input
Running the change detection of the child component, so that the component changes are detected, using componentRef.changeDetectorRef.detectChanges();
rendered component
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;
}
directive
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 snippet
...
<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>
...