diff --git a/projects/ngx-datatable/src/lib/components/body/body-row-wrapper.component.ts b/projects/ngx-datatable/src/lib/components/body/body-row-wrapper.component.ts
index c529fa924..b7fb4e5d1 100644
--- a/projects/ngx-datatable/src/lib/components/body/body-row-wrapper.component.ts
+++ b/projects/ngx-datatable/src/lib/components/body/body-row-wrapper.component.ts
@@ -2,27 +2,24 @@ import { NgTemplateOutlet } from '@angular/common';
import {
booleanAttribute,
ChangeDetectionStrategy,
- ChangeDetectorRef,
Component,
DoCheck,
ElementRef,
- EventEmitter,
HostListener,
inject,
- Input,
IterableDiffer,
IterableDiffers,
KeyValueDiffer,
KeyValueDiffers,
- OnChanges,
OnInit,
- Output,
signal,
- SimpleChanges,
- ViewChild
+ input,
+ output,
+ viewChild,
+ linkedSignal
} from '@angular/core';
-import { Group, GroupContext, Row, RowDetailContext, RowOrGroup } from '../../types/public.types';
+import { Group, Row, RowOrGroup, RowDetailContext, GroupContext } from '../../types/public.types';
import { DATATABLE_COMPONENT_TOKEN } from '../../utils/table-token';
import { DatatableRowDetailDirective } from '../row-detail/row-detail.directive';
import { DatatableGroupHeaderDirective } from './body-group-header.directive';
@@ -31,20 +28,22 @@ import { DatatableGroupHeaderDirective } from './body-group-header.directive';
selector: 'datatable-row-wrapper',
imports: [NgTemplateOutlet],
template: `
- @if (isGroup(row) && groupHeader?.template) {
+ @let row = this.row();
+ @let groupHeader = this.groupHeader();
+ @if (isGroup(row) && groupHeader && groupHeader.template) {
}
- @if ((groupHeader?.template && expanded) || !groupHeader || !groupHeader.template) {
+ @if ((groupHeader?.template && expanded()) || !groupHeader || !groupHeader?.template) {
}
- @let rowDetailTemplate = rowDetail?.template();
- @if (rowDetailTemplate && expanded) {
-
-
+ @let rowDetailTemplate = rowDetail()?.template();
+ @if (rowDetailTemplate && expanded()) {
+
+
}
`,
@@ -74,33 +73,47 @@ import { DatatableGroupHeaderDirective } from './body-group-header.directive';
class: 'datatable-row-wrapper'
}
})
-export class DataTableRowWrapperComponent
- implements DoCheck, OnInit, OnChanges
-{
- @ViewChild('select') checkBoxInput!: ElementRef;
- @Input() innerWidth!: number;
- @Input() rowDetail?: DatatableRowDetailDirective;
- @Input() groupHeader?: DatatableGroupHeaderDirective;
- @Input() offsetX!: number;
- @Input() detailRowHeight!: number;
- @Input() groupHeaderRowHeight!: number;
- @Input() row!: RowOrGroup;
- @Input() groupedRows?: Group[];
- @Input() selected!: TRow[];
- @Input() disabled?: boolean;
- @Output() readonly rowContextmenu = new EventEmitter<{
+export class DataTableRowWrapperComponent implements DoCheck, OnInit {
+ readonly checkBoxInput = viewChild>('select');
+ readonly innerWidth = input.required();
+ readonly rowDetail = input();
+ readonly groupHeader = input();
+ readonly offsetX = input.required();
+ readonly detailRowHeight = input.required();
+ readonly groupHeaderRowHeight = input.required();
+ readonly row = input.required>();
+ readonly groupedRows = input[]>();
+ readonly selected = input.required();
+ readonly disabled = input();
+ readonly rowContextmenu = output<{
event: MouseEvent;
row: RowOrGroup;
- }>(false);
+ }>();
- @Input() rowIndex!: number;
+ readonly rowIndex = input.required();
readonly selectedGroupRows = signal([]);
- @Input({ transform: booleanAttribute }) expanded = false;
- @Input({ required: true }) ariaGroupHeaderCheckboxMessage!: string;
+ readonly expanded = input(false, { transform: booleanAttribute });
+ readonly ariaGroupHeaderCheckboxMessage = input.required();
- context!: RowDetailContext | GroupContext;
+ readonly context = linkedSignal | GroupContext>(() => {
+ const row = this.row();
+ if (this.isGroup(row)) {
+ return {
+ group: row,
+ expanded: this.expanded(),
+ rowIndex: this.rowIndex()
+ };
+ } else {
+ return {
+ row,
+ expanded: this.expanded(),
+ rowIndex: this.rowIndex(),
+ disabled: this.disabled()
+ };
+ }
+ });
private rowDiffer: KeyValueDiffer, any> = inject(KeyValueDiffers)
.find({})
@@ -108,65 +121,48 @@ export class DataTableRowWrapperComponent
private iterableDiffers = inject(IterableDiffers);
private selectedRowsDiffer!: IterableDiffer;
private tableComponent = inject(DATATABLE_COMPONENT_TOKEN);
- private cd = inject(ChangeDetectorRef);
-
- ngOnChanges(changes: SimpleChanges): void {
- if (changes.row) {
- // this component renders either a group header or a row. Never both.
- if (this.isGroup(this.row)) {
- this.context = {
- group: this.row,
- expanded: this.expanded,
- rowIndex: this.rowIndex
- };
- } else {
- this.context = {
- row: this.row,
- expanded: this.expanded,
- rowIndex: this.rowIndex,
- disabled: this.disabled
- };
- }
- }
- if (changes.rowIndex) {
- this.context.rowIndex = this.rowIndex;
- }
- if (changes.expanded) {
- this.context.expanded = this.expanded;
- }
- }
ngOnInit(): void {
- this.selectedRowsDiffer = this.iterableDiffers.find(this.selected ?? []).create();
+ this.selectedRowsDiffer = this.iterableDiffers.find(this.selected() ?? []).create();
}
ngDoCheck(): void {
- if (this.rowDiffer.diff(this.row)) {
- if ('group' in this.context) {
- this.context.group = this.row as Group;
+ const row = this.row();
+ if (this.rowDiffer.diff(row)) {
+ if ('group' in this.context()) {
+ this.context.set({
+ group: row as Group,
+ expanded: this.expanded(),
+ rowIndex: this.rowIndex()
+ });
} else {
- this.context.row = this.row as TRow;
+ this.context.set({
+ row: row as TRow,
+ expanded: this.expanded(),
+ rowIndex: this.rowIndex(),
+ disabled: this.disabled()
+ });
}
- this.cd.markForCheck();
}
// When groupheader is used with chechbox we use iterableDiffer
// on currently selected rows to check if it is modified
// if any of the row of this group is not present in `selected` rows array
// mark group header checkbox state as indeterminate
if (
- this.isGroup(this.row) &&
- this.groupHeader?.checkboxable &&
- this.selectedRowsDiffer.diff(this.selected)
+ this.isGroup(row) &&
+ this.groupHeader()?.checkboxable &&
+ this.selectedRowsDiffer.diff(this.selected())
) {
- const thisRow = this.row;
- const selectedRows = this.selected.filter(row =>
- thisRow.value.find((item: TRow) => item === row)
+ const thisRow = row;
+ const selectedRows = this.selected().filter(rowItem =>
+ thisRow.value.find((item: TRow) => item === rowItem)
);
- if (this.checkBoxInput) {
- if (selectedRows.length && selectedRows.length !== this.row.value.length) {
- this.checkBoxInput.nativeElement.indeterminate = true;
+ const checkBoxInput = this.checkBoxInput();
+ if (checkBoxInput) {
+ if (selectedRows.length && selectedRows.length !== row.value.length) {
+ checkBoxInput.nativeElement.indeterminate = true;
} else {
- this.checkBoxInput.nativeElement.indeterminate = false;
+ checkBoxInput.nativeElement.indeterminate = false;
}
}
this.selectedGroupRows.set(selectedRows);
@@ -175,27 +171,27 @@ export class DataTableRowWrapperComponent
@HostListener('contextmenu', ['$event'])
onContextmenu($event: MouseEvent): void {
- this.rowContextmenu.emit({ event: $event, row: this.row });
+ this.rowContextmenu.emit({ event: $event, row: this.row() });
}
onCheckboxChange(groupSelected: boolean, group: Group): void {
// First remove all rows of this group from `selected`
- this.selected = [
- ...this.selected.filter(row => !group.value.find((item: TRow) => item === row))
+ let selected = [
+ ...this.selected().filter(row => !group.value.find((item: TRow) => item === row))
];
// If checkbox is checked then add all rows of this group in `selected`
if (groupSelected) {
- this.selected = [...this.selected, ...group.value];
+ selected = [...this.selected(), ...group.value];
}
// Update `selected` of DatatableComponent with newly evaluated `selected`
- this.tableComponent.selected = [...this.selected];
+ this.tableComponent.selected = [...selected];
// Emit select event with updated values
this.tableComponent.onBodySelect({
- selected: this.selected
+ selected: [...selected]
});
}
isGroup(row: RowOrGroup): row is Group {
- return !!this.groupHeader;
+ return !!this.groupHeader();
}
}