Skip to content

Commit

Permalink
feat(ngrid): new api to add/remove columns
Browse files Browse the repository at this point in the history
refactor(ngrid) remove hideColumns input from ngrid and use a directive for it
feat(ngrid): new api to control rows (RowsApi)
feat(ngrid): new onConstructed event fired after the grid is constructed but before it is initialized

BREAKING CHANGE:
If you used the hideColumns property (setter only) via code and not via html binding it will no longer work.
Instead, use the new api to add/remove columns.
If you used it via bindings, it will still work but it is not recommended because other plugins that use the API
will override values from the array provided.
  • Loading branch information
shlomiassaf committed Dec 3, 2020
1 parent 916cb95 commit 7a79b2e
Show file tree
Hide file tree
Showing 42 changed files with 725 additions and 434 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export class DemoActionRowComponent implements AfterViewInit {
}

restore(): void {
this.grid.hideColumns = [];
this.grid.columnApi.showColumns(true);
this.grid.invalidateColumns();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,7 @@ export class MatExcelStyleHeaderMenu {
}

hide(): void {
const hidden: string[] = [this.column.id];

for (const col of this.grid.columnApi.columns) {
if (col.hidden) {
hidden.push(col.id);
}
}

this.grid.hideColumns = hidden;
this.grid.columnApi.hideColumns(this.column.id);
}

onSortToggle(sort: 'asc' | 'desc'): void {
Expand All @@ -77,7 +69,6 @@ export class MatExcelStyleHeaderMenu {
}
}


filterColumn(filterValue: string) {
this.currentFilter = filterValue;
if (!filterValue) {
Expand Down
17 changes: 8 additions & 9 deletions libs/ngrid/detail-row/src/lib/detail-row/detail-row-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ export class PblNgridDetailRowPluginDirective<T> implements OnDestroy {
private _defaultParentRef: ComponentRef<PblNgridDefaultDetailRowParentComponent>;
private _removePlugin: (grid: PblNgridComponent<any>) => void;

constructor(private grid: PblNgridComponent<any>, pluginCtrl: PblNgridPluginController<T>, private injector: Injector) {
constructor(private grid: PblNgridComponent<any>, private pluginCtrl: PblNgridPluginController<T>, private injector: Injector) {
this._removePlugin = pluginCtrl.setPlugin(PLUGIN_KEY, this);

pluginCtrl.onInit()
Expand All @@ -147,11 +147,11 @@ export class PblNgridDetailRowPluginDirective<T> implements OnDestroy {
switch (c.type) {
case 'detailRowParent':
if (c.op === 'remove') {
grid._cdkTable.removeRowDef(c.value);
this.pluginCtrl.extApi.cdkTable.removeRowDef(c.value);
this._detailRowDef = undefined;
}
this.setupDetailRowParent();
// grid._cdkTable.syncRows('data');
// grid.rowsApi.syncRows('data');
break;
}
}
Expand Down Expand Up @@ -208,7 +208,7 @@ export class PblNgridDetailRowPluginDirective<T> implements OnDestroy {

private setupDetailRowParent(): void {
const grid = this.grid;
const cdkTable = grid._cdkTable;
const cdkTable = this.pluginCtrl.extApi.cdkTable;
if (this._detailRowDef) {
cdkTable.removeRowDef(this._detailRowDef);
this._detailRowDef = undefined;
Expand All @@ -233,11 +233,10 @@ export class PblNgridDetailRowPluginDirective<T> implements OnDestroy {
}

private resetTableRowDefs(): void {
const grid = this.grid;
if (this._detailRowDef) {
this._detailRow === false
? grid._cdkTable.removeRowDef(this._detailRowDef)
: grid._cdkTable.addRowDef(this._detailRowDef)
? this.pluginCtrl.extApi.cdkTable.removeRowDef(this._detailRowDef)
: this.pluginCtrl.extApi.cdkTable.addRowDef(this._detailRowDef)
;
}
}
Expand All @@ -251,14 +250,14 @@ export class PblNgridDetailRowPluginDirective<T> implements OnDestroy {
this.setupDetailRowParent();
// Once we changed the `when` predicate on the `CdkRowDef` we must:
// 1. Update the row cache (property `rowDefs`) to reflect the new change
this.grid._cdkTable.updateRowDefCache();
this.pluginCtrl.extApi.cdkTable.updateRowDefCache();

// 2. re-render all rows.
// The logic for re-rendering all rows is handled in `CdkTable._forceRenderDataRows()` which is a private method.
// This is a workaround, assigning to `multiTemplateDataRows` will invoke the setter which
// also calls `CdkTable._forceRenderDataRows()`
// TODO: This is risky, the setter logic might change.
// for example, if material will chack for change in `multiTemplateDataRows` setter from previous value...
this.grid._cdkTable.multiTemplateDataRows = !!this._detailRow;
this.pluginCtrl.extApi.cdkTable.multiTemplateDataRows = !!this._detailRow;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,11 @@ export class PblNgridRowReorderPluginDirective<T = any> extends CdkDropList<T> i

this.grid.contextApi.clear();
this.grid.ds.moveItem(previousIndex, currentIndex, true);
this.grid._cdkTable.syncRows('data');
this.grid.rowsApi.syncRows('data');
});
}

/* CdkLazyDropList start */
//#region CdkLazyDropList
/**
* Selector that will be used to determine the direct container element, starting from
* the `cdkDropList` element and going down the DOM. Passing an alternate direct container element
Expand All @@ -102,7 +102,7 @@ export class PblNgridRowReorderPluginDirective<T = any> extends CdkDropList<T> i
addDrag(drag: CdkDrag): void { return CdkLazyDropList.prototype.addDrag.call(this, drag); }
removeDrag(drag: CdkDrag): void { return CdkLazyDropList.prototype.removeDrag.call(this, drag); }
beforeStarted(): void { CdkLazyDropList.prototype.beforeStarted.call(this); }
/* CdkLazyDropList end */
//#endregion CdkLazyDropList

ngOnDestroy(): void {
super.ngOnDestroy();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ export class PblInfiniteScrollDSContext<T, TData = any> {
private deferSyncRows(ms = 0, runBefore?: () => void, runAfter?: () => void) {
this.safeAsyncOp(() => {
runBefore && runBefore();
this.ds.hostGrid._cdkTable.syncRows('data', true);
this.ds.hostGrid.rowsApi.syncRows('data', true);
runAfter && runAfter();
}, ms);
}
Expand Down
14 changes: 7 additions & 7 deletions libs/ngrid/infinite-scroll/src/lib/infinite-scroll-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export class PblNgridInfiniteScrollPlugin<T = any> {
private _infiniteVirtualRowRef: ComponentRef<PblNgridDefaultInfiniteVirtualRowComponent>;
private _removePlugin: (grid: PblNgridComponent<any>) => void;

constructor(private grid: PblNgridComponent<any>, pluginCtrl: PblNgridPluginController<T>, private injector: Injector) {
constructor(private grid: PblNgridComponent<any>, private pluginCtrl: PblNgridPluginController<T>, private injector: Injector) {
this._removePlugin = pluginCtrl.setPlugin(PLUGIN_KEY, this);

grid.registry.changes
Expand All @@ -47,7 +47,7 @@ export class PblNgridInfiniteScrollPlugin<T = any> {
switch (c.type) {
case 'infiniteVirtualRow':
if (c.op === 'remove') {
grid._cdkTable.removeRowDef(c.value);
this.pluginCtrl.extApi.cdkTable.removeRowDef(c.value);
this._infiniteVirtualRowDef = undefined;
}
this.setupInfiniteVirtualRow();
Expand Down Expand Up @@ -75,7 +75,7 @@ export class PblNgridInfiniteScrollPlugin<T = any> {

private setupInfiniteVirtualRow(): void {
const grid = this.grid;
const cdkTable = grid._cdkTable;
const cdkTable = this.pluginCtrl.extApi.cdkTable;
if (this._infiniteVirtualRowDef) {
cdkTable.removeRowDef(this._infiniteVirtualRowDef);
this._infiniteVirtualRowDef = undefined;
Expand Down Expand Up @@ -105,8 +105,8 @@ export class PblNgridInfiniteScrollPlugin<T = any> {
const grid = this.grid;
if (this._infiniteVirtualRowDef) {
this._enabled === false
? grid._cdkTable.removeRowDef(this._infiniteVirtualRowDef)
: grid._cdkTable.addRowDef(this._infiniteVirtualRowDef)
? this.pluginCtrl.extApi.cdkTable.removeRowDef(this._infiniteVirtualRowDef)
: this.pluginCtrl.extApi.cdkTable.addRowDef(this._infiniteVirtualRowDef)
;
}
}
Expand All @@ -120,14 +120,14 @@ export class PblNgridInfiniteScrollPlugin<T = any> {
this.setupInfiniteVirtualRow();
// Once we changed the `when` predicate on the `CdkRowDef` we must:
// 1. Update the row cache (property `rowDefs`) to reflect the new change
this.grid._cdkTable.updateRowDefCache();
this.pluginCtrl.extApi.cdkTable.updateRowDefCache();

// 2. re-render all rows.
// The logic for re-rendering all rows is handled in `CdkTable._forceRenderDataRows()` which is a private method.
// This is a workaround, assigning to `multiTemplateDataRows` will invoke the setter which
// also calls `CdkTable._forceRenderDataRows()`
// TODO: This is risky, the setter logic might change.
// for example, if material will check for change in `multiTemplateDataRows` setter from previous value...
this.grid._cdkTable.multiTemplateDataRows = !!this._enabled;
this.pluginCtrl.extApi.cdkTable.multiTemplateDataRows = !!this._enabled;
}
}
2 changes: 2 additions & 0 deletions libs/ngrid/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ export {
PblNgridFocusChangedEvent, PblNgridSelectionChangedEvent,
PblNgridMetaCellContext, PblNgridCellContext, PblNgridRowContext, PblRowContext, PblNgridContextApi,
CellReference, GridDataPoint,

RowsApi,
} from './lib/grid/index';

export {
Expand Down
15 changes: 13 additions & 2 deletions libs/ngrid/src/lib/ext/grid-ext-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import { InjectionToken } from '@angular/core';
import { PblCdkTableComponent } from '../grid/pbl-cdk-table/pbl-cdk-table.component';
import { ContextApi } from '../grid/context/api';
import { PblNgridComponent } from '../grid/ngrid.component';
import { PblColumnStore } from '../grid/columns/column-store';
import { ColumnApi, PblColumnStore } from '../grid/column-management';
import { DynamicColumnWidthLogic } from '../grid/col-width-logic/dynamic-column-width';
import { PblCdkVirtualScrollViewportComponent } from '../grid/features/virtual-scroll/virtual-scroll-viewport.component'
import { PblNgridEvents } from './types';
import { PblNgridMetaRowService } from '../grid/meta-rows/index';
import { RowsApi } from '../grid/rows-api';
import { PblNgridPluginContext } from './plugin-control';

export const EXT_API_TOKEN = new InjectionToken('PBL_NGRID_EXTERNAL_API');

Expand All @@ -18,9 +20,18 @@ export interface PblNgridExtensionApi<T = any> {
cdkTable: PblCdkTableComponent<T>;
columnStore: PblColumnStore;
contextApi: ContextApi<T>;
columnApi: ColumnApi<T>;
rowsApi: RowsApi<T>;
events: Observable<PblNgridEvents>;
metaRowService: PblNgridMetaRowService;
onConstructed(fn: () => void): void;
onInit(fn: () => void): void;
setViewport(viewport: PblCdkVirtualScrollViewportComponent): void;
dynamicColumnWidthFactory(): DynamicColumnWidthLogic;
}

export interface PblNgridInternalExtensionApi<T = any> extends PblNgridExtensionApi<T> {
viewport: PblCdkVirtualScrollViewportComponent;
plugin: PblNgridPluginContext;
setViewport(viewport: PblCdkVirtualScrollViewportComponent): void;
setCdkTable(cdkTable: PblCdkTableComponent<T>): void;
}
38 changes: 15 additions & 23 deletions libs/ngrid/src/lib/ext/plugin-control.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,33 @@ const CREATED$ = new Subject<{ table: PblNgridComponent<any>, controller: PblNgr

const REGISTERED_TO_CREATE = new WeakSet<any>();

const ON_INIT_PIPE = (o: Observable<PblNgridEvents>) => o.pipe(filter( e => e.kind === 'onInit' ), take(1));

/** @internal */
export class PblNgridPluginContext<T = any> {

// workaround, we need a parameter-less constructor since @ngtools/webpack@8.0.4
// Non @Injectable classes are now getting addded with hard reference to the ctor params which at the class creation point are undefined
// forwardRef() will not help since it's not inject by angular, we instantiate the class..
// probably due to https://github.com/angular/angular-cli/commit/639198499973e0f437f059b3c933c72c733d93d8
static create<T = any>(table: PblNgridComponent<any>, injector: Injector, extApi: PblNgridExtensionApi): PblNgridPluginContext<T> {
if (NGRID_PLUGIN_CONTEXT.has(table)) {
static create<T = any>(injector: Injector, extApi: PblNgridExtensionApi) {
if (NGRID_PLUGIN_CONTEXT.has(extApi.grid)) {
throw new Error(`Table is already registered for extensions.`);
}

const instance = new PblNgridPluginContext<T>();
NGRID_PLUGIN_CONTEXT.set(table, instance);
NGRID_PLUGIN_CONTEXT.set(extApi.grid, instance);

instance.grid = table;
instance.grid = extApi.grid;
instance.injector = injector;
instance.extApi = extApi;
PblNgridPluginController.create<T>(instance);

return instance;
instance.controller = new PblNgridPluginController<T>(instance);

return {
plugin: instance,
init: () => CREATED$.next({ table: instance.grid, controller: instance.controller }),
};
}

grid: PblNgridComponent<any>;
Expand Down Expand Up @@ -66,6 +72,7 @@ export class PblNgridPluginContext<T = any> {
}

export class PblNgridPluginController<T = any> {

static readonly created = CREATED$.asObservable();

static onCreatedSafe(token: any, fn: (grid: PblNgridComponent<any>, controller: PblNgridPluginController<any>) => void) {
Expand All @@ -75,20 +82,14 @@ export class PblNgridPluginController<T = any> {
}
}

static create<T = any>(context: PblNgridPluginContext<T>) {
const controller = new PblNgridPluginController<T>(context);
context.controller = controller;
CREATED$.next({ table: context.grid, controller });
}

get injector(): Injector { return this.context.injector; }

readonly extApi: PblNgridExtensionApi
readonly events: Observable<PblNgridEvents>;
private readonly grid: PblNgridComponent<T>
private readonly plugins = new Map<keyof PblNgridPluginExtension, PblNgridPlugin>();

private constructor(private context: PblNgridPluginContext) {
constructor(private context: PblNgridPluginContext) {
this.grid = context.grid;
this.extApi = context.extApi;
this.events = context.events;
Expand All @@ -106,16 +107,7 @@ export class PblNgridPluginController<T = any> {
* In other words, if you get false, it means you called this method when the grid was already initialized.
*/
onInit() {
if (this.grid.isInit) {
return of(false);
}

return this.events
.pipe(
filter( e => e.kind === 'onInit' ),
take(1),
mapTo(true),
);
return this.grid.isInit ? of(false) : this.events.pipe(ON_INIT_PIPE, mapTo(true));
}

static find<T = any>(grid: PblNgridComponent<T>): PblNgridPluginController<T> | undefined {
Expand Down
12 changes: 12 additions & 0 deletions libs/ngrid/src/lib/ext/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,17 @@ export interface PblNgridPluginExtension { }

export interface PblNgridPluginExtensionFactories { }

/**
* This event is fired after the grid has constructed, including the main internal grid component and the viewport.
* > Note that the components we're constructed, not initialized!
*/
export interface PblNgridOnConstructedEvent {
kind: 'onConstructed';
}

/**
* This event is fired after the grid has initialized
*/
export interface PblNgridOnInitEvent {
kind: 'onInit';
}
Expand Down Expand Up @@ -34,6 +45,7 @@ export interface PblNgridOnDataSourceEvent {
}

export type PblNgridEvents =
| PblNgridOnConstructedEvent
| PblNgridOnInitEvent
| PblNgridOnResizeRowEvent
| PblNgridBeforeInvalidateHeadersEvent
Expand Down
Loading

0 comments on commit 7a79b2e

Please sign in to comment.