Skip to content

Commit

Permalink
feat(remote): add Remote Model example with custom dataview (#115)
Browse files Browse the repository at this point in the history
* feat(remote): add Remote Model example with custom dataview
- this provide access for user to use their own dataview
- the lib uses dataview in it's core, so user will have to re-implement a lot of these features, like file/sort/...

* refactor(remote): add Remote Model demo to Github build

* refactor(build): fix a build warning

* refactor(remote): simplify creation of grid with dataview
  • Loading branch information
ghiscoding committed Dec 1, 2018
1 parent 1676d7c commit 7cc2faa
Show file tree
Hide file tree
Showing 9 changed files with 344 additions and 3 deletions.
9 changes: 6 additions & 3 deletions aurelia-slickgrid/src/aurelia-slickgrid/aurelia-slickgrid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ export class AureliaSlickgridCustomElement {
@bindable({ defaultBindingMode: bindingMode.twoWay }) gridPaginationOptions: GridOption;
@bindable({ defaultBindingMode: bindingMode.twoWay }) dataview: any;
@bindable({ defaultBindingMode: bindingMode.twoWay }) grid: any;
@bindable() customDataview: any;
@bindable() dataset: any[];
@bindable() gridId: string;
@bindable() gridOptions: GridOption;
Expand Down Expand Up @@ -166,7 +167,9 @@ export class AureliaSlickgridCustomElement {
this.sharedService.allColumns = this._columnDefinitions;
this.sharedService.visibleColumns = this._columnDefinitions;
this.extensionService.createCheckboxPluginBeforeGridCreation(this._columnDefinitions, this.gridOptions);
this.grid = new Slick.Grid(`#${this.gridId}`, this.dataview, this._columnDefinitions, this.gridOptions);

// build SlickGrid Grid, also user might optionally pass a custom dataview (e.g. remote model)
this.grid = new Slick.Grid(`#${this.gridId}`, this.customDataview || this.dataview, this._columnDefinitions, this.gridOptions);

this.sharedService.dataView = this.dataview;
this.sharedService.grid = this.grid;
Expand Down Expand Up @@ -394,12 +397,12 @@ export class AureliaSlickgridCustomElement {
}

// attach external sorting (backend) when available or default onSort (dataView)
if (gridOptions.enableSorting) {
if (gridOptions.enableSorting && !this.customDataview) {
gridOptions.backendServiceApi ? this.sortService.attachBackendOnSort(grid, dataView) : this.sortService.attachLocalOnSort(grid, dataView);
}

// attach external filter (backend) when available or default onFilter (dataView)
if (gridOptions.enableFiltering) {
if (gridOptions.enableFiltering && !this.customDataview) {
this.filterService.init(grid);

// if user entered some "presets", we need to reflect them all in the DOM
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -369,5 +369,6 @@ export class GridService {

return gridIdx;
}
return -1;
}
}
32 changes: 32 additions & 0 deletions aurelia-slickgrid/src/examples/slickgrid/example17.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<template>
<h2>${title}</h2>
<div class="subtitle"
innerhtml.bind="subTitle"></div>

<hr>

<div class="col-md-6"
style="margin-bottom: 15px">
<label>Octopart Catalog Search <small>(throttle search to 1.5sec)</small></label>
<input type="text"
class="form-control"
value.bind="search & throttle:1500">
</div>

<div class="alert alert-warning col-md-6"
role="alert"
if.bind="loading">
<i class="fa fa-refresh fa-spin fa-lg fa-fw"></i>
<span>Loading...</span>
</div>

<aurelia-slickgrid grid-id="grid1"
column-definitions.bind="columnDefinitions"
grid-options.bind="gridOptions"
dataset.bind="dataset"
custom-dataview.bind="customDataView"
asg-on-aurelia-grid-created.delegate="aureliaGridReady($event.detail)"
sg-on-viewport-changed.delegate="onViewportChanged($event.detail.eventData, $event.detail.args)"
sg-on-sort.delegate="onSort($event.detail.eventData, $event.detail.args)">
</aurelia-slickgrid>
</template>
135 changes: 135 additions & 0 deletions aurelia-slickgrid/src/examples/slickgrid/example17.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import 'slickgrid/lib/jquery.jsonp-2.4.min';
import 'slickgrid/slick.remotemodel'; // SlickGrid Remote Plugin
import { bindable, bindingMode } from 'aurelia-framework';
import { AureliaGridInstance, Column, Formatter, GridOption } from '../../aurelia-slickgrid';

declare var Slick: any;

const brandFormatter: Formatter = (row: number, cell: number, value: any, columnDef: Column, dataContext: any) => {
return dataContext && dataContext.brand && dataContext.brand.name || '';
};

const mpnFormatter: Formatter = (row: number, cell: number, value: any, columnDef: Column, dataContext: any) => {
let link = '';
if (dataContext && dataContext.octopart_url && dataContext.mpn) {
link = `<a href="${dataContext.octopart_url}" target="_blank">${dataContext.mpn}</a>`;
}
return link;
};

export class Example17 {
@bindable({ defaultBindingMode: bindingMode.twoWay }) search = 'switch';
private _eventHandler: any = new Slick.EventHandler();

title = 'Example 17: Octopart Catalog Search - Remote Model Plugin';
subTitle = `
This example demonstrates how to use "slick.remotemodel.js" or any Remote implementation through an external Remote Service
<ul>
<li>If the demo throws some errors, try again later (there's a limit per day)</li>
<li>
Uses <a href="https://github.com/6pac/SlickGrid/blob/master/slick.remotemodel.js" target="_blank">slick.remotemodel.js</a>
which is hooked up to load search results from Octopart, but can easily be extended
to support any JSONP-compatible backend that accepts paging parameters.
</li>
</ul>
`;
aureliaGrid: AureliaGridInstance;
columnDefinitions: Column[];
customDataView: any;
dataset = [];
gridObj: any;
gridOptions: GridOption;
loaderDataView: any;
loading = false; // spinner when loading data

constructor() {
// define the grid options & columns and then create the grid itself
this.defineGrid();
this.loaderDataView = new Slick.Data.RemoteModel();
this.customDataView = this.loaderDataView && this.loaderDataView.data;
}

attached() {
this.hookAllLoaderEvents();
this.loaderDataView.setSearch(this.search);
}

detached() {
// unsubscribe all SlickGrid events
this._eventHandler.unsubscribeAll();
}

aureliaGridReady(aureliaGrid: any) {
this.aureliaGrid = aureliaGrid;
this.gridObj = aureliaGrid.slickGrid; // grid object
this.loaderDataView.setSort('score', -1);
this.gridObj.setSortColumn('score', false);

// notify of a change to preload the first page
this.gridObj.onViewportChanged.notify();
}

defineGrid() {
this.columnDefinitions = [
{ id: 'mpn', name: 'MPN', field: 'mpn', formatter: mpnFormatter, width: 100, sortable: true },
{ id: 'brand', name: 'Brand', field: 'brand.name', formatter: brandFormatter, width: 100, sortable: true },
{ id: 'short_description', name: 'Description', field: 'short_description', width: 520 },
];

this.gridOptions = {
enableAutoResize: true,
autoResize: {
containerId: 'demo-container',
sidePadding: 15
},
enableCellNavigation: true,
enableColumnReorder: false,
enableGridMenu: false,
multiColumnSort: false
};
}

hookAllLoaderEvents() {
if (this._eventHandler && this._eventHandler.subscribe && this.loaderDataView && this.loaderDataView.onDataLoading && this.loaderDataView.onDataLoaded) {
this._eventHandler.subscribe(this.loaderDataView.onDataLoading, (e: Event, args: any) => {
this.loading = true;
});

this._eventHandler.subscribe(this.loaderDataView.onDataLoaded, (e: Event, args: any) => {
if (args && args.from && args.to && this.gridObj && this.gridObj.invalidateRow && this.gridObj.updateRowCount && this.gridObj.render) {
for (let i = args.from; i <= args.to; i++) {
this.gridObj.invalidateRow(i);
}
this.gridObj.updateRowCount();
this.gridObj.render();
this.loading = false;
}
});
}
}

searchChanged(newValue: string) {
if (newValue && this.gridObj && this.gridObj.getViewport && this.loaderDataView && this.loaderDataView.ensureData && this.loaderDataView.setSearch) {
const vp = this.gridObj.getViewport();
this.loaderDataView.setSearch(newValue);
this.loaderDataView.ensureData(vp.top, vp.bottom);
}
}

onSort(e, args) {
if (this.gridObj && this.gridObj.getViewport && this.loaderDataView && this.loaderDataView.ensureData && this.loaderDataView.setSort) {
const vp = this.gridObj.getViewport();
if (args && args.sortCol && args.sortCol.field) {
this.loaderDataView.setSort(args.sortCol.field, args.sortAsc ? 1 : -1);
}
this.loaderDataView.ensureData(vp.top, vp.bottom);
}
}

onViewportChanged(e, args) {
if (this.gridObj && this.gridObj.getViewport && this.loaderDataView && this.loaderDataView.ensureData) {
const vp = this.gridObj.getViewport();
this.loaderDataView.ensureData(vp.top, vp.bottom);
}
}
}
1 change: 1 addition & 0 deletions aurelia-slickgrid/src/examples/slickgrid/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export class Index {
{ route: 'example14', moduleId: PLATFORM.moduleName('./example14'), name: 'example14', nav: true, title: '14- Column Span & Header Grouping' },
{ route: 'example15', moduleId: PLATFORM.moduleName('./example15'), name: 'example15', nav: true, title: '15- Grid State & Local Storage' },
{ route: 'example16', moduleId: PLATFORM.moduleName('./example16'), name: 'example16', nav: true, title: '16- Row Move Plugin' },
{ route: 'example17', moduleId: PLATFORM.moduleName('./example17'), name: 'example17', nav: true, title: '17- Remote Model' },
];

config.map(mapping);
Expand Down
1 change: 1 addition & 0 deletions doc/github-demo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
"nps-utils": "1.5.0",
"opn": "^5.2.0",
"sass-loader": "^6.0.7",
"slickgrid": "^2.3.21",
"style-loader": "0.20.3",
"through2": "^2.0.3",
"ts-node": "^5.0.1",
Expand Down
32 changes: 32 additions & 0 deletions doc/github-demo/src/examples/slickgrid/example17.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<template>
<h2>${title}</h2>
<div class="subtitle"
innerhtml.bind="subTitle"></div>

<hr>

<div class="col-md-6"
style="margin-bottom: 15px">
<label>Octopart Catalog Search <small>(throttle search to 1.5sec)</small></label>
<input type="text"
class="form-control"
value.bind="search & throttle:1500">
</div>

<div class="alert alert-warning col-md-6"
role="alert"
if.bind="loading">
<i class="fa fa-refresh fa-spin fa-lg fa-fw"></i>
<span>Loading...</span>
</div>

<aurelia-slickgrid grid-id="grid1"
column-definitions.bind="columnDefinitions"
grid-options.bind="gridOptions"
dataset.bind="dataset"
custom-dataview.bind="customDataView"
asg-on-aurelia-grid-created.delegate="aureliaGridReady($event.detail)"
sg-on-viewport-changed.delegate="onViewportChanged($event.detail.eventData, $event.detail.args)"
sg-on-sort.delegate="onSort($event.detail.eventData, $event.detail.args)">
</aurelia-slickgrid>
</template>
135 changes: 135 additions & 0 deletions doc/github-demo/src/examples/slickgrid/example17.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import 'slickgrid/lib/jquery.jsonp-2.4.min';
import 'slickgrid/slick.remotemodel'; // SlickGrid Remote Plugin
import { bindable, bindingMode } from 'aurelia-framework';
import { AureliaGridInstance, Column, Formatter, GridOption } from 'aurelia-slickgrid';

declare var Slick: any;

const brandFormatter: Formatter = (row: number, cell: number, value: any, columnDef: Column, dataContext: any) => {
return dataContext && dataContext.brand && dataContext.brand.name || '';
};

const mpnFormatter: Formatter = (row: number, cell: number, value: any, columnDef: Column, dataContext: any) => {
let link = '';
if (dataContext && dataContext.octopart_url && dataContext.mpn) {
link = `<a href="${dataContext.octopart_url}" target="_blank">${dataContext.mpn}</a>`;
}
return link;
};

export class Example17 {
@bindable({ defaultBindingMode: bindingMode.twoWay }) search = 'switch';
private _eventHandler: any = new Slick.EventHandler();

title = 'Example 17: Octopart Catalog Search - Remote Model Plugin';
subTitle = `
This example demonstrates how to use "slick.remotemodel.js" or any Remote implementation through an external Remote Service
<ul>
<li>If the demo throws some errors, try again later (there's a limit per day)</li>
<li>
Uses <a href="https://github.com/6pac/SlickGrid/blob/master/slick.remotemodel.js" target="_blank">slick.remotemodel.js</a>
which is hooked up to load search results from Octopart, but can easily be extended
to support any JSONP-compatible backend that accepts paging parameters.
</li>
</ul>
`;
aureliaGrid: AureliaGridInstance;
columnDefinitions: Column[];
customDataView: any;
dataset = [];
gridObj: any;
gridOptions: GridOption;
loaderDataView: any;
loading = false; // spinner when loading data

constructor() {
// define the grid options & columns and then create the grid itself
this.defineGrid();
this.loaderDataView = new Slick.Data.RemoteModel();
this.customDataView = this.loaderDataView && this.loaderDataView.data;
}

attached() {
this.hookAllLoaderEvents();
this.loaderDataView.setSearch(this.search);
}

detached() {
// unsubscribe all SlickGrid events
this._eventHandler.unsubscribeAll();
}

aureliaGridReady(aureliaGrid: any) {
this.aureliaGrid = aureliaGrid;
this.gridObj = aureliaGrid.slickGrid; // grid object
this.loaderDataView.setSort('score', -1);
this.gridObj.setSortColumn('score', false);

// notify of a change to preload the first page
this.gridObj.onViewportChanged.notify();
}

defineGrid() {
this.columnDefinitions = [
{ id: 'mpn', name: 'MPN', field: 'mpn', formatter: mpnFormatter, width: 100, sortable: true },
{ id: 'brand', name: 'Brand', field: 'brand.name', formatter: brandFormatter, width: 100, sortable: true },
{ id: 'short_description', name: 'Description', field: 'short_description', width: 520 },
];

this.gridOptions = {
enableAutoResize: true,
autoResize: {
containerId: 'demo-container',
sidePadding: 15
},
enableCellNavigation: true,
enableColumnReorder: false,
enableGridMenu: false,
multiColumnSort: false
};
}

hookAllLoaderEvents() {
if (this._eventHandler && this._eventHandler.subscribe && this.loaderDataView && this.loaderDataView.onDataLoading && this.loaderDataView.onDataLoaded) {
this._eventHandler.subscribe(this.loaderDataView.onDataLoading, (e: Event, args: any) => {
this.loading = true;
});

this._eventHandler.subscribe(this.loaderDataView.onDataLoaded, (e: Event, args: any) => {
if (args && args.from && args.to && this.gridObj && this.gridObj.invalidateRow && this.gridObj.updateRowCount && this.gridObj.render) {
for (let i = args.from; i <= args.to; i++) {
this.gridObj.invalidateRow(i);
}
this.gridObj.updateRowCount();
this.gridObj.render();
this.loading = false;
}
});
}
}

searchChanged(newValue: string) {
if (newValue && this.gridObj && this.gridObj.getViewport && this.loaderDataView && this.loaderDataView.ensureData && this.loaderDataView.setSearch) {
const vp = this.gridObj.getViewport();
this.loaderDataView.setSearch(newValue);
this.loaderDataView.ensureData(vp.top, vp.bottom);
}
}

onSort(e, args) {
if (this.gridObj && this.gridObj.getViewport && this.loaderDataView && this.loaderDataView.ensureData && this.loaderDataView.setSort) {
const vp = this.gridObj.getViewport();
if (args && args.sortCol && args.sortCol.field) {
this.loaderDataView.setSort(args.sortCol.field, args.sortAsc ? 1 : -1);
}
this.loaderDataView.ensureData(vp.top, vp.bottom);
}
}

onViewportChanged(e, args) {
if (this.gridObj && this.gridObj.getViewport && this.loaderDataView && this.loaderDataView.ensureData) {
const vp = this.gridObj.getViewport();
this.loaderDataView.ensureData(vp.top, vp.bottom);
}
}
}

0 comments on commit 7cc2faa

Please sign in to comment.