Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: apply even/odd classes correctly when rows are grouped #111

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
} from '../../types/public.types';
import { DataTableGhostLoaderComponent } from './ghost-loader/ghost-loader.component';
import { AsyncPipe, NgTemplateOutlet } from '@angular/common';
import { RowIndex } from '../../types/internal.types';

@Component({
selector: 'datatable-body-cell',
Expand Down Expand Up @@ -157,14 +158,15 @@ export class DataTableBodyCellComponent<TRow extends { level?: number } = any>
return this._expanded;
}

@Input() set rowIndex(val: number) {
@Input() set rowIndex(val: RowIndex) {
this._rowIndex = val;
this.cellContext.rowIndex = val;
this.cellContext.rowIndex = val?.index;
this.cellContext.rowInGroupIndex = val?.indexInGroup;
this.checkValueUpdates();
this.cd.markForCheck();
}

get rowIndex(): number {
get rowIndex(): RowIndex {
return this._rowIndex;
}

Expand Down Expand Up @@ -314,7 +316,7 @@ export class DataTableBodyCellComponent<TRow extends { level?: number } = any>
private _row: TRow;
private _group: TRow[];
private _rowHeight: number;
private _rowIndex: number;
private _rowIndex: RowIndex;
private _expanded: boolean;
private _element = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;
private _treeStatus: TreeStatus;
Expand All @@ -329,7 +331,8 @@ export class DataTableBodyCellComponent<TRow extends { level?: number } = any>
column: this.column,
rowHeight: this.rowHeight,
isSelected: this.isSelected,
rowIndex: this.rowIndex,
rowIndex: this.rowIndex?.index,
rowInGroupIndex: this.rowIndex?.indexInGroup,
treeStatus: this.treeStatus,
disable$: this.disable$,
onTreeAction: () => this.onTreeAction()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,60 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { DataTableBodyRowComponent } from './body-row.component';
import { DataTableBodyCellComponent } from './body-cell.component';
import { Component } from '@angular/core';
import { ScrollbarHelper } from '../../services/scrollbar-helper.service';
import { TableColumn } from '../../types/table-column.type';
import { By } from '@angular/platform-browser';
import { RowIndex } from '../../types/internal.types';

describe('DataTableBodyRowComponent', () => {
let fixture: ComponentFixture<DataTableBodyRowComponent>;
let component: DataTableBodyRowComponent;
@Component({
template: ` <datatable-body-row [rowIndex]="rowIndex" [row]="row" [columns]="columns" /> `,
imports: [DataTableBodyRowComponent],
standalone: true
})
class TestHostComponent {
rowIndex: RowIndex = { index: 0 };
row: any = { prop: 'value' };
columns: TableColumn[] = [{ prop: 'prop', $$valueGetter: () => 'value' }];
}

let fixture: ComponentFixture<TestHostComponent>;
let component: TestHostComponent;

// provide our implementations or mocks to the dependency injector
beforeEach(() => {
TestBed.configureTestingModule({
imports: [DataTableBodyCellComponent, DataTableBodyRowComponent]
imports: [TestHostComponent],
providers: [ScrollbarHelper]
});
});

beforeEach(waitForAsync(() => {
TestBed.compileComponents().then(() => {
fixture = TestBed.createComponent(DataTableBodyRowComponent);
fixture = TestBed.createComponent(TestHostComponent);
component = fixture.componentInstance;
});
}));

describe('fixture', () => {
it('should have a component instance', () => {
expect(component).toBeTruthy();
});
it('should apply odd/event without groups', () => {
component.rowIndex = { index: 0 };
fixture.detectChanges();
const element = fixture.debugElement.query(By.directive(DataTableBodyRowComponent))
.nativeElement as HTMLElement;
expect(element.classList).toContain('datatable-row-even');
component.rowIndex = { index: 3 };
fixture.detectChanges();
expect(element.classList).toContain('datatable-row-odd');
});

it('should apply event odd/even if row is grouped', () => {
component.rowIndex = { index: 1, indexInGroup: 0 };
fixture.detectChanges();
const element = fixture.debugElement.query(By.directive(DataTableBodyRowComponent))
.nativeElement as HTMLElement;
expect(element.classList).toContain('datatable-row-even');
component.rowIndex = { index: 666, indexInGroup: 3 };
fixture.detectChanges();
expect(element.classList).toContain('datatable-row-odd');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { BehaviorSubject } from 'rxjs';
import { ActivateEvent, RowOrGroup, TreeStatus } from '../../types/public.types';
import { AsyncPipe } from '@angular/common';
import { TableColumn } from '../../types/table-column.type';
import { ColumnGroupWidth, PinnedColumns } from '../../types/internal.types';
import { ColumnGroupWidth, PinnedColumns, RowIndex } from '../../types/internal.types';
import { DataTableBodyCellComponent } from './body-cell.component';

@Component({
Expand Down Expand Up @@ -92,7 +92,7 @@ export class DataTableBodyRowComponent<TRow = any> implements DoCheck, OnChanges
@Input() row: TRow;
@Input() group: TRow[];
@Input() isSelected: boolean;
@Input() rowIndex: number;
@Input() rowIndex: RowIndex | undefined;
@Input() displayCheck: (row: TRow, column: TableColumn, value?: any) => boolean;
@Input() treeStatus?: TreeStatus = 'collapsed';
@Input() ghostLoadingIndicator = false;
Expand All @@ -113,10 +113,10 @@ export class DataTableBodyRowComponent<TRow = any> implements DoCheck, OnChanges
if (this.isSelected) {
cls += ' active';
}
if (this.rowIndex % 2 !== 0) {
if (this.innerRowIndex % 2 !== 0) {
cls += ' datatable-row-odd';
}
if (this.rowIndex % 2 === 0) {
if (this.innerRowIndex % 2 === 0) {
cls += ' datatable-row-even';
}
if (this.disable$ && this.disable$.value) {
Expand Down Expand Up @@ -228,4 +228,12 @@ export class DataTableBodyRowComponent<TRow = any> implements DoCheck, OnChanges
onTreeAction() {
this.treeAction.emit();
}

/** Returns the row index, or if in a group, the index within a group. */
private get innerRowIndex(): number {
if (!this.rowIndex) {
return 0;
}
return this.rowIndex.indexInGroup ?? this.rowIndex.index;
}
}
34 changes: 16 additions & 18 deletions projects/ngx-datatable/src/lib/components/body/body.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { TableColumn } from '../../types/table-column.type';
import { DatatableGroupHeaderDirective } from './body-group-header.directive';
import { DatatableRowDetailDirective } from '../row-detail/row-detail.directive';
import { DataTableBodyRowComponent } from './body-row.component';
import { ColumnGroupWidth } from '../../types/internal.types';
import { ColumnGroupWidth, RowIndex } from '../../types/internal.types';
import {
ActivateEvent,
DragEventData,
Expand All @@ -39,7 +39,6 @@ import { DataTableRowWrapperComponent } from './body-row-wrapper.component';
import { DataTableSummaryRowComponent } from './summary/summary-row.component';
import { DataTableSelectionComponent } from './selection.component';
import { DataTableGhostLoaderComponent } from './ghost-loader/ghost-loader.component';
import { ProgressBarComponent } from './progress-bar.component';

@Component({
selector: 'datatable-body',
Expand Down Expand Up @@ -108,7 +107,7 @@ import { ProgressBarComponent } from './progress-bar.component';
[row]="group"
[disableCheck]="disableRowCheck"
[expanded]="getRowExpanded(group)"
[rowIndex]="getRowIndex(group && group[i])"
[rowIndex]="getRowIndex(group && group[i])?.index ?? 0"
[selected]="selected"
(rowContextmenu)="rowContextmenu.emit($event)"
>
Expand Down Expand Up @@ -256,7 +255,6 @@ import { ProgressBarComponent } from './progress-bar.component';
},
standalone: true,
imports: [
ProgressBarComponent,
DataTableGhostLoaderComponent,
DataTableSelectionComponent,
ScrollerComponent,
Expand Down Expand Up @@ -433,7 +431,7 @@ export class DataTableBodyComponent<TRow extends { treeStatus?: TreeStatus } = a
columnGroupWidths: ColumnGroupWidth;
rowTrackingFn: TrackByFunction<RowOrGroup<TRow>>;
listener: any;
rowIndexes = new WeakMap<any, any>();
rowIndexes = new WeakMap<RowOrGroup<TRow>, RowIndex>();
rowExpansions: any[] = [];

_rows: TRow[];
Expand All @@ -459,8 +457,7 @@ export class DataTableBodyComponent<TRow extends { treeStatus?: TreeStatus } = a
if (this.trackByProp) {
return row[this.trackByProp];
} else {
const idx = this.getRowIndex(row);
return idx;
return this.getRowIndex(row)?.index;
}
};
}
Expand Down Expand Up @@ -600,13 +597,12 @@ export class DataTableBodyComponent<TRow extends { treeStatus?: TreeStatus } = a
while (rowIndex < last && rowIndex < this.groupedRows.length) {
// Add the groups into this page
const group = this.groupedRows[rowIndex];
this.rowIndexes.set(group, rowIndex);
this.rowIndexes.set(group, { index: rowIndex });

if (group.value) {
// add indexes for each group item
group.value.forEach((g: any, i: number) => {
const _idx = `${rowIndex}-${i}`;
this.rowIndexes.set(g, _idx);
group.value.forEach((g: TRow, i: number) => {
this.rowIndexes.set(g, { index: rowIndex, indexInGroup: i });
});
}
temp[idx] = group;
Expand All @@ -621,7 +617,7 @@ export class DataTableBodyComponent<TRow extends { treeStatus?: TreeStatus } = a

if (row) {
// add indexes for each row
this.rowIndexes.set(row, rowIndex);
this.rowIndexes.set(row, { index: rowIndex });
temp[idx] = row;
} else if (this.ghostLoadingIndicator && this.virtualization) {
temp[idx] = undefined;
Expand Down Expand Up @@ -730,10 +726,12 @@ export class DataTableBodyComponent<TRow extends { treeStatus?: TreeStatus } = a
if (Array.isArray(rows)) {
// Get the latest row rowindex in a group
const row = rows[rows.length - 1];
idx = row ? this.getRowIndex(row) : 0;
// The group row, which has always a numeric index
idx = row ? this.getRowIndex(row).index : 0;
} else {
if (rows) {
idx = this.getRowIndex(rows);
// normal rows always have a numeric index
idx = this.getRowIndex(rows).index;
} else {
// When ghost cells are enabled use index to get the position of them
idx = this.indexes().first + index;
Expand Down Expand Up @@ -872,8 +870,8 @@ export class DataTableBodyComponent<TRow extends { treeStatus?: TreeStatus } = a
// If the detailRowHeight is auto --> only in case of non-virtualized scroll
if (this.scrollbarV && this.virtualization) {
const detailRowHeight = this.getDetailRowHeight(row) * (expanded ? -1 : 1);
// const idx = this.rowIndexes.get(row) || 0;
const idx = this.getRowIndex(row);
// This is hopefully only called with non-grouped rows. Otherwise, the heightCache fails.
const idx = this.getRowIndex(row).index;
this.rowHeightsCache().update(idx, detailRowHeight);
}

Expand Down Expand Up @@ -954,8 +952,8 @@ export class DataTableBodyComponent<TRow extends { treeStatus?: TreeStatus } = a
/**
* Gets the row index given a row
*/
getRowIndex(row: RowOrGroup<TRow>): number {
return this.rowIndexes.get(row) || 0;
getRowIndex(row: RowOrGroup<TRow>): RowIndex | undefined {
return this.rowIndexes.get(row);
}

onTreeAction(row: TRow) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ function noopSumFunc(cells: any[]): void {
[columns]="_internalColumns"
[rowHeight]="rowHeight"
[row]="summaryRow"
[rowIndex]="-1"
[rowIndex]="{ index: -1 }"
>
</datatable-body-row>
}
Expand Down
8 changes: 8 additions & 0 deletions projects/ngx-datatable/src/lib/types/internal.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,11 @@ export interface DraggableDragEvent {
element: HTMLElement;
model: TableColumn;
}

/** Represents the index of a row. */
export interface RowIndex {
/** Index of the row. If the row is inside a group, it will hold the index the group. */
index: number;
/** Index of a row inside a group. Only present if the row is inside a group. */
indexInGroup?: number;
}
1 change: 1 addition & 0 deletions projects/ngx-datatable/src/lib/types/public.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export interface CellContext<TRow = any> {
rowHeight: number;
isSelected: boolean;
rowIndex: number;
rowInGroupIndex?: number;
treeStatus: TreeStatus;
disable$: BehaviorSubject<boolean>;
onTreeAction: () => void;
Expand Down
Loading