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

feat(datagrid): optimise layout rendering #1346

Merged
merged 4 commits into from
May 9, 2024
Merged
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
26 changes: 18 additions & 8 deletions projects/angular/clarity.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -2216,14 +2216,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 @@ -4984,10 +4984,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 @@ -5016,14 +5020,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 @@ -5044,11 +5052,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 @@ -1030,6 +1030,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
Loading