Skip to content

Commit

Permalink
feat(datagrid): optimise layout rendering (backport to 16.x) (#1391)
Browse files Browse the repository at this point in the history
backport of #1346

---------

Co-authored-by: GitHub <noreply@github.com>
  • Loading branch information
dtsanevmw and web-flow authored May 28, 2024
1 parent d2c267a commit f13f4a5
Show file tree
Hide file tree
Showing 21 changed files with 165 additions and 146 deletions.
26 changes: 18 additions & 8 deletions projects/angular/clarity.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -2214,14 +2214,14 @@ export class ClrExpandableAnimation {
// Warning: (ae-forgotten-export) The symbol "DomAdapter" needs to be exported by the entry point index.d.ts
constructor(element: ElementRef, domAdapter: DomAdapter, renderer: Renderer2);
// (undocumented)
animationDone(): void;
animationDone(event: AnimationEvent_2): void;
// (undocumented)
animationStart(): void;
animationStart(event: AnimationEvent_2): void;
// (undocumented)
clrExpandTrigger: any;
clrExpandTrigger: boolean;
// (undocumented)
get expandAnimation(): {
value: any;
value: boolean;
params: {
startHeight: number;
};
Expand Down Expand Up @@ -4989,10 +4989,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 @@ -5021,14 +5025,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 @@ -5049,11 +5057,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 @@ -1841,6 +1841,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: 0 additions & 2 deletions projects/angular/src/data/datagrid/datagrid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,8 +304,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 @@ -10,6 +10,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 @@ -6,12 +6,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 @@ -26,38 +24,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 @@ -69,23 +64,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 @@ -6,9 +6,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 @@ -18,7 +18,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 @@ -28,50 +27,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 @@ -80,11 +49,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 @@ -102,12 +102,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 @@ -129,19 +129,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 f13f4a5

Please sign in to comment.