Skip to content

Commit

Permalink
feat(datagrid): optimise layout rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
dtsanevmw committed Apr 8, 2024
1 parent 0c02a7a commit cec3051
Show file tree
Hide file tree
Showing 16 changed files with 153 additions and 137 deletions.
20 changes: 15 additions & 5 deletions projects/angular/clarity.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1725,7 +1725,7 @@ export class ClrDatagridRow<T = any> implements AfterContentInit, AfterViewInit
// (undocumented)
expandAnimation: ClrExpandableAnimation;
// (undocumented)
expandAnimationTrigger: boolean;
expandAnimationTrigger: boolean | null;
// (undocumented)
get expanded(): boolean | string;
set expanded(value: boolean | string);
Expand Down Expand Up @@ -4972,10 +4972,14 @@ export class ÇlrClrPopoverOpenCloseButton implements OnDestroy {
export class ÇlrDatagridCellRenderer implements OnDestroy {
constructor(el: ElementRef, renderer: Renderer2, organizer: DatagridRenderOrganizer);
// (undocumented)
set columnState(columnState: BehaviorSubject<ColumnState>);
// (undocumented)
ngOnDestroy(): void;
// (undocumented)
resetState(state: ColumnState): void;
// (undocumented)
setHidden(state: ColumnState): void;
// (undocumented)
setWidth(state: ColumnState): void;
// (undocumented)
static ɵdir: i0.ɵɵDirectiveDeclaration<ÇlrDatagridCellRenderer, "clr-dg-cell", never, {}, {}, never, never, false, never>;
// (undocumented)
static ɵfac: i0.ɵɵFactoryDeclaration<ÇlrDatagridCellRenderer, never>;
Expand Down Expand Up @@ -5004,14 +5008,18 @@ export class ÇlrDatagridHeaderRenderer implements OnDestroy {
// (undocumented)
setColumnState(index: number): void;
// (undocumented)
setHidden(state: ColumnState): void;
// (undocumented)
setWidth(state: ColumnState): void;
// (undocumented)
static ɵdir: i0.ɵɵDirectiveDeclaration<ÇlrDatagridHeaderRenderer, "clr-dg-column", never, {}, { "resizeEmitter": "clrDgColumnResize"; }, never, never, false, never>;
// (undocumented)
static ɵfac: i0.ɵɵFactoryDeclaration<ÇlrDatagridHeaderRenderer, never>;
}

// @public (undocumented)
export class ÇlrDatagridMainRenderer implements AfterContentInit, AfterViewInit, AfterViewChecked, OnDestroy {
constructor(organizer: DatagridRenderOrganizer, items: Items, page: Page, domAdapter: DomAdapter, el: ElementRef, renderer: Renderer2, detailService: DetailService, tableSizeService: TableSizeService, columnsService: ColumnsService, ngZone: NgZone);
constructor(organizer: DatagridRenderOrganizer, items: Items, page: Page, domAdapter: DomAdapter, el: ElementRef, renderer: Renderer2, detailService: DetailService, tableSizeService: TableSizeService, columnsService: ColumnsService, ngZone: NgZone, keyNavigation: KeyNavigationGridController);
// (undocumented)
ngAfterContentInit(): void;
// (undocumented)
Expand All @@ -5032,11 +5040,13 @@ export class ÇlrDatagridMainRenderer implements AfterContentInit, AfterViewInit
export class ÇlrDatagridRowRenderer implements AfterContentInit, OnDestroy {
constructor(columnsService: ColumnsService);
// (undocumented)
cells: QueryList<ÇlrDatagridCellRenderer>;
// (undocumented)
ngAfterContentInit(): void;
// (undocumented)
ngOnDestroy(): void;
// (undocumented)
setColumnState(): void;
setCellsState(): void;
// (undocumented)
static ɵdir: i0.ɵɵDirectiveDeclaration<ÇlrDatagridRowRenderer, "clr-dg-row, clr-dg-row-detail", never, {}, {}, ["cells"], never, false, never>;
// (undocumented)
Expand Down
4 changes: 4 additions & 0 deletions projects/angular/src/data/datagrid/_datagrid.clarity.scss
Original file line number Diff line number Diff line change
Expand Up @@ -1044,6 +1044,10 @@
flex: 0 0 auto !important;
min-width: 0 !important;
display: block !important;
visibility: hidden !important;
position: absolute !important;
top: 0;
left: 0;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion projects/angular/src/data/datagrid/datagrid-row.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export class ClrDatagridRow<T = any> implements AfterContentInit, AfterViewInit
expandableId: string;
replaced: boolean;
displayCells = false;
expandAnimationTrigger = false;
expandAnimationTrigger: boolean | null = null;

/* reference to the enum so that template can access */
SELECTION_TYPE = SelectionType;
Expand Down
2 changes: 0 additions & 2 deletions projects/angular/src/data/datagrid/datagrid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -303,8 +303,6 @@ export class ClrDatagrid<T = any> implements AfterContentInit, AfterViewInit, On
this.datagridTable.nativeElement.focus();
}
}),
// Reinitialize arrow key navigation on hide/unhide columns
combineLatest(this.columnsService.columns).subscribe(() => this.keyNavigation?.resetKeyGrid()),
// A subscription that listens for displayMode changes on the datagrid
this.displayMode.view.subscribe(viewChange => {
// Remove any projected columns from the projectedDisplayColumns container
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { TemplateRef } from '@angular/core';
import { DatagridColumnChanges } from '../enums/column-changes.enum';

export interface ColumnState {
columnIndex?: number;
changes?: DatagridColumnChanges[]; // This is an array of change types to update
width?: number; // This is the width calculated for the column
strictWidth?: number; // This is the strict width if defined in styles/css
Expand Down
23 changes: 8 additions & 15 deletions projects/angular/src/data/datagrid/render/cell-renderer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,10 @@
*/

import { Component } from '@angular/core';
import { BehaviorSubject } from 'rxjs';

import { DatagridColumnChanges } from '../enums/column-changes.enum';
import { DatagridRenderStep } from '../enums/render-step.enum';
import { TestContext } from '../helpers.spec';
import { ColumnState } from '../interfaces/column-state.interface';
import { DatagridCellRenderer } from './cell-renderer';
import { HIDDEN_COLUMN_CLASS, STRICT_WIDTH_CLASS } from './constants';
import { DatagridRenderOrganizer } from './render-organizer';
Expand All @@ -25,38 +23,35 @@ export default function (): void {
describe('DatagridCellRenderer directive', function () {
let context: TestContext<DatagridCellRenderer, SimpleTest>;
let organizer: MockDatagridRenderOrganizer;
let stateSub: BehaviorSubject<ColumnState>;

beforeEach(function () {
context = this.create(DatagridCellRenderer, SimpleTest, [MOCK_ORGANIZER_PROVIDER]);
organizer = context.getClarityProvider(DatagridRenderOrganizer) as MockDatagridRenderOrganizer;
stateSub = new BehaviorSubject<ColumnState>({});
context.clarityDirective.columnState = stateSub;
});

it('sets proper width and class for strict width cells', function () {
stateSub.next({ changes: [DatagridColumnChanges.WIDTH], width: 42, strictWidth: 42 });
context.clarityDirective.setWidth({ changes: [DatagridColumnChanges.WIDTH], width: 42, strictWidth: 42 });
expect(context.clarityElement.style.width).toBe('42px');
expect(context.clarityElement.classList).toContain(STRICT_WIDTH_CLASS);
});

it('sets proper hidden class for hidden cell', function () {
stateSub.next({ changes: [DatagridColumnChanges.HIDDEN], hidden: true });
context.clarityDirective.setHidden({ changes: [DatagridColumnChanges.HIDDEN], hidden: true });
expect(context.clarityElement.classList).toContain(HIDDEN_COLUMN_CLASS);
stateSub.next({ changes: [DatagridColumnChanges.HIDDEN], hidden: false });
context.clarityDirective.setHidden({ changes: [DatagridColumnChanges.HIDDEN], hidden: false });
expect(context.clarityElement.classList).not.toContain(HIDDEN_COLUMN_CLASS);
});

it('makes the cell non-flexible if and only if the width is strict', function () {
stateSub.next({ changes: [DatagridColumnChanges.WIDTH], width: 42, strictWidth: 42 });
context.clarityDirective.setWidth({ changes: [DatagridColumnChanges.WIDTH], width: 42, strictWidth: 42 });
expect(context.clarityElement.style.width).toBe('42px');
expect(context.clarityElement.classList).toContain(STRICT_WIDTH_CLASS);
stateSub.next({ changes: [DatagridColumnChanges.WIDTH], width: 42, strictWidth: 0 });
context.clarityDirective.setWidth({ changes: [DatagridColumnChanges.WIDTH], width: 42, strictWidth: 0 });
expect(context.clarityElement.classList).not.toContain(STRICT_WIDTH_CLASS);
});

it('resets the cell to default width when notified', function () {
stateSub.next({ changes: [DatagridColumnChanges.WIDTH], width: 42, strictWidth: 42 });
context.clarityDirective.setWidth({ changes: [DatagridColumnChanges.WIDTH], width: 42, strictWidth: 42 });
expect(context.clarityElement.style.width).toBe('42px');
expect(context.clarityElement.classList).toContain(STRICT_WIDTH_CLASS);
organizer.updateRenderStep.next(DatagridRenderStep.CLEAR_WIDTHS);
Expand All @@ -68,23 +63,21 @@ export default function (): void {
expect(context.clarityElement.style.width).toBe('');
expect(context.clarityElement.classList).not.toContain(STRICT_WIDTH_CLASS);
expect(context.clarityElement.classList).not.toContain(HIDDEN_COLUMN_CLASS);
stateSub.next({
context.clarityDirective.resetState({
changes: [DatagridColumnChanges.WIDTH, DatagridColumnChanges.HIDDEN],
width: 84,
strictWidth: 0,
hidden: true,
});
context.clarityDirective.columnState = stateSub;
expect(context.clarityElement.style.width).toBe('84px');
expect(context.clarityElement.classList).not.toContain(STRICT_WIDTH_CLASS);
expect(context.clarityElement.classList).toContain(HIDDEN_COLUMN_CLASS);
stateSub.next({
context.clarityDirective.resetState({
changes: [DatagridColumnChanges.HIDDEN, DatagridColumnChanges.WIDTH],
width: 42,
strictWidth: 42,
hidden: false,
});
context.clarityDirective.columnState = stateSub;
expect(context.clarityElement.style.width).toBe('42px');
expect(context.clarityElement.classList).toContain(STRICT_WIDTH_CLASS);
expect(context.clarityElement.classList).not.toContain(HIDDEN_COLUMN_CLASS);
Expand Down
52 changes: 13 additions & 39 deletions projects/angular/src/data/datagrid/render/cell-renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
*/

import { Directive, ElementRef, OnDestroy, Renderer2 } from '@angular/core';
import { BehaviorSubject, Subscription } from 'rxjs';
import { Subscription } from 'rxjs';

import { ALL_COLUMN_CHANGES, DatagridColumnChanges } from '../enums/column-changes.enum';
import { ALL_COLUMN_CHANGES } from '../enums/column-changes.enum';
import { DatagridRenderStep } from '../enums/render-step.enum';
import { ColumnState } from '../interfaces/column-state.interface';
import { HIDDEN_COLUMN_CLASS, STRICT_WIDTH_CLASS } from './constants';
Expand All @@ -17,7 +17,6 @@ import { DatagridRenderOrganizer } from './render-organizer';
selector: 'clr-dg-cell',
})
export class DatagridCellRenderer implements OnDestroy {
private runAllChanges: DatagridColumnChanges[];
private stateSubscription: Subscription;
private subscriptions: Subscription[] = [];

Expand All @@ -27,50 +26,20 @@ export class DatagridCellRenderer implements OnDestroy {
);
}

// @TODO(JEREMY) Work out how to dedupe some of this code between header and cell renderers
set columnState(columnState: BehaviorSubject<ColumnState>) {
if (this.stateSubscription) {
this.stateSubscription.unsubscribe();
}

this.runAllChanges = ALL_COLUMN_CHANGES;
this.stateSubscription = columnState.subscribe(state => this.stateChanges(state));
}

ngOnDestroy() {
this.subscriptions.forEach(sub => sub.unsubscribe());
if (this.stateSubscription) {
this.stateSubscription.unsubscribe();
}
}

private stateChanges(state: ColumnState) {
if (this.runAllChanges) {
state.changes = this.runAllChanges;
delete this.runAllChanges;
}
if (state.changes && state.changes.length) {
state.changes.forEach(change => {
switch (change) {
case DatagridColumnChanges.WIDTH:
this.setWidth(state);
break;
case DatagridColumnChanges.HIDDEN:
this.setHidden(state);
break;
default:
break;
}
});
}
}

private clearWidth() {
this.renderer.removeClass(this.el.nativeElement, STRICT_WIDTH_CLASS);
this.renderer.setStyle(this.el.nativeElement, 'width', null);
resetState(state: ColumnState) {
state.changes = ALL_COLUMN_CHANGES;
this.setWidth(state);
this.setHidden(state);
}

private setWidth(state: ColumnState) {
setWidth(state: ColumnState) {
if (state.strictWidth) {
this.renderer.addClass(this.el.nativeElement, STRICT_WIDTH_CLASS);
} else {
Expand All @@ -79,11 +48,16 @@ export class DatagridCellRenderer implements OnDestroy {
this.renderer.setStyle(this.el.nativeElement, 'width', state.width + 'px');
}

private setHidden(state: ColumnState) {
setHidden(state: ColumnState) {
if (state.hidden) {
this.renderer.addClass(this.el.nativeElement, HIDDEN_COLUMN_CLASS);
} else {
this.renderer.removeClass(this.el.nativeElement, HIDDEN_COLUMN_CLASS);
}
}

private clearWidth() {
this.renderer.removeClass(this.el.nativeElement, STRICT_WIDTH_CLASS);
this.renderer.setStyle(this.el.nativeElement, 'width', null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,12 @@ export default function (): void {
});

it('can set the width of a column', function () {
stateSub.next({ changes: [DatagridColumnChanges.WIDTH], width: 123 });
context.clarityDirective.setWidth({ changes: [DatagridColumnChanges.WIDTH], width: 123 });
expect(context.clarityElement.style.width).toBe('123px');
});

it('resets the header to default width when notified', function () {
stateSub.next({ changes: [DatagridColumnChanges.WIDTH], width: 123 });
context.clarityDirective.setWidth({ changes: [DatagridColumnChanges.WIDTH], width: 123 });
expect(context.clarityElement.style.width).toBe('123px');
organizer.updateRenderStep.next(DatagridRenderStep.CLEAR_WIDTHS);
expect(context.clarityElement.style.width).toBeFalsy();
Expand All @@ -128,19 +128,19 @@ export default function (): void {

it('does not set the width when the user declared a strict one', function () {
domAdapter._scrollWidth = 123;
stateSub.next({ changes: [DatagridColumnChanges.WIDTH], width: 123, strictWidth: 24 });
context.clarityDirective.setWidth({ changes: [DatagridColumnChanges.WIDTH], width: 123, strictWidth: 24 });
expect(context.clarityElement.classList).toContain(STRICT_WIDTH_CLASS);
expect(context.clarityElement.style.width).toBeFalsy();

stateSub.next({ changes: [DatagridColumnChanges.WIDTH], width: 123, strictWidth: 0 });
context.clarityDirective.setWidth({ changes: [DatagridColumnChanges.WIDTH], width: 123, strictWidth: 0 });
expect(context.clarityElement.style.width).toBe('123px');
expect(context.clarityElement.classList).not.toContain(STRICT_WIDTH_CLASS);
});

it('sets proper hidden class for hidden cell', function () {
stateSub.next({ changes: [DatagridColumnChanges.HIDDEN], hidden: true });
context.clarityDirective.setHidden({ changes: [DatagridColumnChanges.HIDDEN], hidden: true });
expect(context.clarityElement.classList).toContain(HIDDEN_COLUMN_CLASS);
stateSub.next({ changes: [DatagridColumnChanges.HIDDEN], hidden: false });
context.clarityDirective.setHidden({ changes: [DatagridColumnChanges.HIDDEN], hidden: false });
expect(context.clarityElement.classList).not.toContain(HIDDEN_COLUMN_CLASS);
});
});
Expand Down
Loading

0 comments on commit cec3051

Please sign in to comment.