Skip to content

Commit

Permalink
feat(event): #24 add onGridStateChanged and onPaginationChanged events (
Browse files Browse the repository at this point in the history
#28)

* feat(event): add onGridStateChanged and onPaginationChanged events
- add onGridStateChanged
- add onPaginationChanged event that Angular-Slickgrid can then trigger Grid State onGridStateChanged event
- add better onFilterChanged & onSortChanged events

* refactor(event): add aurelia slickgrid event prefix
* refactor(code): remove unnecessary self when bind this is enough
* fix(build): fix Build lib errors of object can be undefined
  • Loading branch information
ghiscoding authored Mar 13, 2018
1 parent 3d21548 commit b657e75
Show file tree
Hide file tree
Showing 14 changed files with 202 additions and 86 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<div id.bind="gridId" class="slickgrid-container" style.bind="style">
</div>

<slick-pagination id="slickPagingContainer-${gridId}" if.bind="showPagination" pagination-options.bind="gridPaginationOptions"></slick-pagination>
<slick-pagination id="slickPagingContainer-${gridId}" if.bind="showPagination" asg-on-pagination-changed.delegate="paginationChanged($event.detail)"
pagination-options.bind="gridPaginationOptions"></slick-pagination>
</div>
</template>
28 changes: 26 additions & 2 deletions aurelia-slickgrid/src/aurelia-slickgrid/aurelia-slickgrid.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { GridStateChange } from './models/gridStateChange.interface';
// import 3rd party vendor libs
import 'slickgrid/lib/jquery-ui-1.11.3';
import 'slickgrid/lib/jquery.event.drag-2.3.0';
Expand Down Expand Up @@ -30,7 +31,9 @@ import {
Column,
FormElementType,
GraphqlResult,
GridOption
GridOption,
GridStateType,
Pagination,
} from './models/index';
import {
ControlAndPluginService,
Expand All @@ -49,13 +52,15 @@ import * as $ from 'jquery';
// using external non-typed js libraries
declare var Slick: any;

const aureliaEventPrefix = 'asg';
const eventPrefix = 'sg';

// Aurelia doesn't support well TypeScript @autoinject in a Plugin so we'll do it the old fashion way
@inject(ControlAndPluginService, ExportService, Element, EventAggregator, FilterService, GraphqlService, GridEventService, GridExtraService, GridStateService, I18N, ResizerService, SortService)
export class AureliaSlickgridCustomElement {
private _dataset: any[];
private _eventHandler: any = new Slick.EventHandler();
gridStateSubscriber: Subscription;
gridHeightString: string;
gridWidthString: string;
localeChangedSubscriber: Subscription;
Expand Down Expand Up @@ -158,11 +163,13 @@ export class AureliaSlickgridCustomElement {
this.dataview = [];
this._eventHandler.unsubscribeAll();
this.controlAndPluginService.dispose();
this.gridEventService.dispose();
this.filterService.dispose();
this.gridEventService.dispose();
this.gridStateService.dispose();
this.resizer.dispose();
this.sortService.dispose();
this.grid.destroy();
this.gridStateSubscriber.dispose();
this.localeChangedSubscriber.dispose();
this.ea.publish('onAfterGridDestroyed', true);
this.elm.dispatchEvent(new CustomEvent(`${eventPrefix}-on-after-grid-destroyed`, {
Expand Down Expand Up @@ -258,6 +265,7 @@ export class AureliaSlickgridCustomElement {
}
}

// expose all Slick Grid Events through dispatch
for (const prop in grid) {
if (grid.hasOwnProperty(prop) && prop.startsWith('on')) {
this._eventHandler.subscribe(grid[prop], (e: any, args: any) => {
Expand All @@ -272,6 +280,7 @@ export class AureliaSlickgridCustomElement {
}
}

// expose all Slick DataView Events through dispatch
for (const prop in dataView) {
if (dataView.hasOwnProperty(prop) && prop.startsWith('on')) {
this._eventHandler.subscribe(dataView[prop], (e: any, args: any) => {
Expand All @@ -286,6 +295,14 @@ export class AureliaSlickgridCustomElement {
}
}

// expose GridState Service changes event through dispatch
this.gridStateSubscriber = this.ea.subscribe('gridStateService:changed', (gridStateChange: GridStateChange) => {
this.elm.dispatchEvent(new CustomEvent(`${aureliaEventPrefix}-on-grid-state-service-changed`, {
bubbles: true,
detail: gridStateChange
}));
});

// on cell click, mainly used with the columnDef.action callback
this.gridEventService.attachOnCellChange(grid, this.gridOptions, dataView);
this.gridEventService.attachOnClick(grid, this.gridOptions, dataView);
Expand Down Expand Up @@ -381,6 +398,13 @@ export class AureliaSlickgridCustomElement {
return $.extend(true, {}, GlobalGridOptions, this.gridOptions);
}

paginationChanged(pagination: Pagination) {
this.ea.publish('gridStateService:changed', {
change: { newValues: pagination, type: GridStateType.pagination },
gridState: this.gridStateService.getCurrentGridState()
});
}

/**
* When dataset changes, we need to refresh the entire grid UI & possibly resize it as well
* @param dataset
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const collectionFormatter: Formatter = (row: number, cell: number, value:
value.map((v: any) => findOrDefault(collection, (c: any) => c[valueName] === v)[labelName]),
columnDef,
dataContext);
}
}

return findOrDefault(collection, (c: any) => c[valueName] === value)[labelName] || '';
};
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { CurrentSorter } from './currentSorter.interface';
import { CurrentFilter } from './currentFilter.interface';
import { CurrentFilter, CurrentSorter } from './../models/index';

export interface GridState {
/** Filters (and their state, columnId, searchTerm(s)) that are currently applied in the grid */
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { CurrentFilter, CurrentSorter, GridState, GridStateType, Pagination } from './../models/index';

export interface GridStateChange {
/** Changes that were triggered */
change?: {
newValues: CurrentFilter[] | CurrentSorter[] | Pagination;
type: GridStateType;
};

/** Current grid state */
gridState?: GridState;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export enum GridStateType {
filter = 'filter',
pagination = 'pagination',
sorter = 'sorter'
}
4 changes: 3 additions & 1 deletion aurelia-slickgrid/src/aurelia-slickgrid/models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,11 @@ export * from './graphqlPaginationOption.interface';
export * from './graphqlResult.interface';
export * from './graphqlServiceOption.interface';
export * from './graphqlSortingOption.interface';
export * from './gridState.interface';
export * from './gridMenu.interface';
export * from './gridOption.interface';
export * from './gridState.interface';
export * from './gridStateChange.interface';
export * from './gridStateType.enum';
export * from './headerButton.interface';
export * from './headerButtonItem.interface';
export * from './headerButtonOnCommandArgs.interface';
Expand Down
95 changes: 53 additions & 42 deletions aurelia-slickgrid/src/aurelia-slickgrid/services/filter.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,18 @@ import * as $ from 'jquery';
// using external non-typed js libraries
declare var Slick: any;

@inject(FilterFactory)
@inject(EventAggregator, FilterFactory)
export class FilterService {
private _eventHandler = new Slick.EventHandler();
private _subscriber: SlickEvent = new Slick.Event();
private _slickSubscriber: SlickEvent;
private _filters: any[] = [];
private _columnFilters: ColumnFilters = {};
private _dataView: any;
private _grid: any;
private _gridOptions: GridOption;
private _onFilterChangedOptions: any;
onFilterChanged = new EventAggregator();

constructor(private filterFactory: FilterFactory) { }
constructor(private ea: EventAggregator, private filterFactory: FilterFactory) { }

init(grid: any, gridOptions: GridOption, columnDefinitions: Column[]): void {
this._grid = grid;
Expand All @@ -47,10 +46,10 @@ export class FilterService {
*/
attachBackendOnFilter(grid: any, options: GridOption) {
this._filters = [];
this.emitFilterChangedBy('remote');
this._slickSubscriber = new Slick.Event();

this._subscriber = new Slick.Event();
this._subscriber.subscribe(this.attachBackendOnFilterSubscribe);
// subscribe to the SlickGrid event and call the backend execution
this._slickSubscriber.subscribe(this.attachBackendOnFilterSubscribe.bind(this));

// subscribe to SlickGrid onHeaderRowCellRendered event to create filter template
this._eventHandler.subscribe(grid.onHeaderRowCellRendered, (e: Event, args: any) => {
Expand All @@ -77,6 +76,9 @@ export class FilterService {
// call the service to get a query back
const query = await backendApi.service.onFilterChanged(event, args);

// emit an onFilterChanged event
this.emitFilterChanged('remote');

// await for the Promise to resolve the data
const processResult = await backendApi.process(query);

Expand All @@ -91,6 +93,34 @@ export class FilterService {
}
}

/**
* Attach a local filter hook to the grid
* @param grid SlickGrid Grid object
* @param gridOptions Grid Options object
* @param dataView
*/
attachLocalOnFilter(grid: any, options: GridOption, dataView: any) {
this._filters = [];
this._dataView = dataView;
this._slickSubscriber = new Slick.Event();

dataView.setFilterArgs({ columnFilters: this._columnFilters, grid: this._grid });
dataView.setFilter(this.customLocalFilter.bind(this, dataView));

this._slickSubscriber.subscribe((e: any, args: any) => {
const columnId = args.columnId;
if (columnId != null) {
dataView.refresh();
}
this.emitFilterChanged('local');
});

// subscribe to SlickGrid onHeaderRowCellRendered event to create filter template
this._eventHandler.subscribe(grid.onHeaderRowCellRendered, (e: Event, args: any) => {
this.addFilterTemplateToHeaderRow(args);
});
}

/** Clear the search filters (below the column titles) */
clearFilters() {
this._filters.forEach((filter, index) => {
Expand All @@ -116,34 +146,6 @@ export class FilterService {
}
}

/**
* Attach a local filter hook to the grid
* @param grid SlickGrid Grid object
* @param gridOptions Grid Options object
* @param dataView
*/
attachLocalOnFilter(grid: any, options: GridOption, dataView: any) {
this._dataView = dataView;
this._filters = [];
this.emitFilterChangedBy('local');

dataView.setFilterArgs({ columnFilters: this._columnFilters, grid: this._grid });
dataView.setFilter(this.customLocalFilter.bind(this, dataView));

this._subscriber = new Slick.Event();
this._subscriber.subscribe((e: any, args: any) => {
const columnId = args.columnId;
if (columnId != null) {
dataView.refresh();
}
});

// subscribe to SlickGrid onHeaderRowCellRendered event to create filter template
this._eventHandler.subscribe(grid.onHeaderRowCellRendered, (e: Event, args: any) => {
this.addFilterTemplateToHeaderRow(args);
});
}

customLocalFilter(dataView: any, item: any, args: any) {
for (const columnId of Object.keys(args.columnFilters)) {
const columnFilter = args.columnFilters[columnId];
Expand Down Expand Up @@ -236,8 +238,8 @@ export class FilterService {
this._eventHandler.unsubscribeAll();

// unsubscribe local event
if (this._subscriber && typeof this._subscriber.unsubscribe === 'function') {
this._subscriber.unsubscribe();
if (this._slickSubscriber && typeof this._slickSubscriber.unsubscribe === 'function') {
this._slickSubscriber.unsubscribe();
}
}

Expand Down Expand Up @@ -302,7 +304,7 @@ export class FilterService {
};
}

this.triggerEvent(this._subscriber, {
this.triggerEvent(this._slickSubscriber, {
columnId,
columnDef: args.columnDef || null,
columnFilters: this._columnFilters,
Expand Down Expand Up @@ -378,12 +380,21 @@ export class FilterService {
}

/**
* A simple function that is attached to the subscriber and emit a change when the sort is called.
* A simple function that will be called to emit a change when a filter changes.
* Other services, like Pagination, can then subscribe to it.
* @param {string} sender
* @param sender
*/
emitFilterChangedBy(sender: string) {
this._subscriber.subscribe(() => this.onFilterChanged.publish('filterService:changed', `onFilterChanged by ${sender}`));
emitFilterChanged(sender: 'local' | 'remote') {
if (sender === 'remote' && this._gridOptions && this._gridOptions.backendServiceApi) {
let currentFilters: CurrentFilter[] = [];
const backendService = this._gridOptions.backendServiceApi.service;
if (backendService && backendService.getCurrentFilters) {
currentFilters = backendService.getCurrentFilters() as CurrentFilter[];
}
this.ea.publish('filterService:filterChanged', currentFilters);
} else if (sender === 'local') {
this.ea.publish('filterService:filterChanged', this.getCurrentLocalFilters());
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
import { inject } from 'aurelia-framework';
import {
CurrentFilter,
CurrentPagination,
CurrentSorter,
GridOption,
GridState
GridState,
GridStateType,
} from './../models/index';
import { FilterService, SortService } from './../services/index';
import { EventAggregator, Subscription } from 'aurelia-event-aggregator';
import * as $ from 'jquery';

@inject(EventAggregator)
export class GridStateService {
private _grid: any;
private _gridOptions: GridOption;
private _preset: GridState;
private filterService: FilterService;
private _filterSubcription: Subscription;
private _sorterSubcription: Subscription;
private sortService: SortService;

constructor(private ea: EventAggregator) { }

/**
* Initialize the Export Service
* @param grid
Expand All @@ -26,6 +34,19 @@ export class GridStateService {
this.filterService = filterService;
this.sortService = sortService;
this._gridOptions = (grid && grid.getOptions) ? grid.getOptions() : {};

// Subscribe to Event Emitter of Filter & Sort changed, go back to page 1 when that happen
this._filterSubcription = this.ea.subscribe('filterService:filterChanged', (currentFilters: CurrentFilter[]) => {
this.ea.publish('gridStateService:changed', { change: { newValues: currentFilters, type: GridStateType.filter }, gridState: this.getCurrentGridState() });
});
this._sorterSubcription = this.ea.subscribe('sortService:sortChanged', (currentSorters: CurrentSorter[]) => {
this.ea.publish('gridStateService:changed', { change: { newValues: currentSorters, type: GridStateType.sorter }, gridState: this.getCurrentGridState() });
});
}

dispose() {
this._filterSubcription.dispose();
this._sorterSubcription.dispose();
}

/**
Expand Down
Loading

0 comments on commit b657e75

Please sign in to comment.