Skip to content
This repository was archived by the owner on Jun 1, 2025. It is now read-only.

Commit 32eece4

Browse files
Ghislain BeaulacGhislain Beaulac
authored andcommitted
refactor(remote): add more customDataView check in lib & update example
1 parent a220d91 commit 32eece4

File tree

5 files changed

+154
-135
lines changed

5 files changed

+154
-135
lines changed

src/app/examples/grid-remote.component.html

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,16 @@
33
<h2>{{title}}</h2>
44
<div class="subtitle" [innerHTML]="subTitle"></div>
55

6-
<div class="col-md-12">
7-
<div class="alert alert-warning col-md-6" role="alert" *ngIf="loading">
8-
<i class="fa fa-refresh fa-spin fa-lg fa-fw"></i>
9-
<span>Loading...</span>
10-
</div>
11-
<div class="alert alert-info col-md-6" role="alert" *ngIf="!loading">
12-
<span>Ready</span>
13-
</div>
6+
<div class="col-md-6" style="margin-bottom: 15px">
7+
<label>Octopart Catalog Search <small>(type a word then press ENTER)</small></label>
8+
<input type="text" class="form-control" [value]="search" (change)="searchChanged($event.target.value)">
149
</div>
1510

16-
<div class="col-md-6">
17-
<label>Octopart Catalog Search <small>(type a word then press ENTER)</small></label>
18-
<input type="text" id="txtSearch" class="form-control" value="switch">
11+
<div class="alert alert-warning col-md-6"
12+
role="alert"
13+
*ngIf="loading">
14+
<i class="fa fa-refresh fa-spin fa-lg fa-fw"></i>
15+
<span>Loading...</span>
1916
</div>
2017

2118
<angular-slickgrid
Lines changed: 74 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
import 'slickgrid/lib/jquery.jsonp-2.4.min';
22
import 'slickgrid/slick.remotemodel'; // SlickGrid Remote Plugin
33

4-
import { Component, OnInit } from '@angular/core';
4+
import { Component, OnInit, OnDestroy } from '@angular/core';
55
import { AngularGridInstance, Column, Formatter, GridOption } from './../modules/angular-slickgrid';
66

7-
declare var $: any;
87
declare var Slick: any;
98

109
const brandFormatter: Formatter = (row: number, cell: number, value: any, columnDef: Column, dataContext: any) => {
@@ -13,7 +12,7 @@ const brandFormatter: Formatter = (row: number, cell: number, value: any, column
1312

1413
const mpnFormatter: Formatter = (row: number, cell: number, value: any, columnDef: Column, dataContext: any) => {
1514
let link = '';
16-
if (dataContext && dataContext.octopart_url && dataContext.mpn) {
15+
if (dataContext && dataContext.octopart_url && dataContext.mpn) {
1716
link = `<a href="${dataContext.octopart_url}" target="_blank">${dataContext.mpn}</a>`;
1817
}
1918
return link;
@@ -22,14 +21,28 @@ const mpnFormatter: Formatter = (row: number, cell: number, value: any, columnDe
2221
@Component({
2322
templateUrl: './grid-remote.component.html'
2423
})
25-
export class GridRemoteComponent implements OnInit {
26-
title = 'Example 18: Remote Model Plugin';
24+
export class GridRemoteComponent implements OnDestroy, OnInit {
25+
private _eventHandler: any = new Slick.EventHandler();
26+
27+
title = 'Example 18: Octopart Catalog Search - Remote Model Plugin';
2728
subTitle = `
28-
This example demonstrates how to use "slick.remotemodel.js" or any Remote implementation through an external Remote Service
29-
<ul>
30-
<li>
31-
</li>
32-
</ul>
29+
This example demonstrates how to use "slick.remotemodel.js" or any Remote implementation through an external Remote Service
30+
<ul>
31+
<li>Your browser might block access to the Octopart query, if you get "block content" then just unblock it.</li>
32+
<li>If the demo throws some errors, try again later (there's a limit per day).</li>
33+
<li>
34+
Uses <a href="https://github.com/6pac/SlickGrid/blob/master/slick.remotemodel.js" target="_blank">slick.remotemodel.js</a>
35+
which is hooked up to load search results from Octopart, but can easily be extended
36+
to support any JSONP-compatible backend that accepts paging parameters.
37+
</li>
38+
<li>
39+
This demo implements a custom DataView, however please note that you are on your own to implement all necessary DataView methods
40+
for Sorting, Filtering, etc...
41+
</li>
42+
<li>
43+
Soure code for this example is available <a href="https://github.com/ghiscoding/aurelia-slickgrid/blob/master/doc/github-demo/src/examples/slickgrid/example17.ts" target="_blank">here</a>
44+
</li>
45+
</ul>
3346
`;
3447

3548
angularGrid: AngularGridInstance;
@@ -40,33 +53,39 @@ export class GridRemoteComponent implements OnInit {
4053
dataset = [];
4154
loaderDataView: any;
4255
loading = false; // spinner when loading data
56+
search = 'switch';
4357

4458
constructor() {
4559
this.loaderDataView = new Slick.Data.RemoteModel();
4660
this.customDataView = this.loaderDataView && this.loaderDataView.data;
4761
}
4862

49-
angularGridReady(angularGrid: any) {
63+
angularGridReady(angularGrid: AngularGridInstance) {
5064
this.angularGrid = angularGrid;
5165
this.gridObj = angularGrid.slickGrid; // grid object
52-
5366
this.loaderDataView.setSort('score', -1);
5467
this.gridObj.setSortColumn('score', false);
55-
// load the first page
68+
69+
// notify of a change to preload the first page
5670
this.gridObj.onViewportChanged.notify();
5771
}
5872

73+
ngOnDestroy() {
74+
// unsubscribe all SlickGrid events
75+
this._eventHandler.unsubscribeAll();
76+
}
77+
5978
ngOnInit(): void {
60-
this.prepareDataGrid();
79+
this.defineGrid();
6180
this.hookAllLoaderEvents();
62-
this.hookSearch();
81+
this.loaderDataView.setSearch(this.search);
6382
}
6483

65-
prepareDataGrid() {
84+
defineGrid() {
6685
this.columnDefinitions = [
67-
{id: 'mpn', name: 'MPN', field: 'mpn', formatter: mpnFormatter, width: 100, sortable: true },
68-
{id: 'brand', name: 'Brand', field: 'brand.name', formatter: brandFormatter, width: 100, sortable: true },
69-
{id: 'short_description', name: 'Description', field: 'short_description', width: 520 },
86+
{ id: 'mpn', name: 'MPN', field: 'mpn', formatter: mpnFormatter, width: 100, sortable: true },
87+
{ id: 'brand', name: 'Brand', field: 'brand.name', formatter: brandFormatter, width: 100, sortable: true },
88+
{ id: 'short_description', name: 'Description', field: 'short_description', width: 520 },
7089
];
7190

7291
this.gridOptions = {
@@ -76,65 +95,53 @@ export class GridRemoteComponent implements OnInit {
7695
sidePadding: 15
7796
},
7897
enableCellNavigation: true,
79-
enableColumnReorder: false
98+
enableColumnReorder: false,
99+
enableGridMenu: false,
100+
multiColumnSort: false
80101
};
81-
82-
this.getData();
83-
}
84-
85-
getData() {
86-
// Set up some test columns.
87-
const mockDataset = [];
88-
for (let i = 0; i < 500; i++) {
89-
mockDataset[i] = {
90-
id: i,
91-
title: 'Task ' + i,
92-
duration: '5 days',
93-
percentComplete: Math.round(Math.random() * 100),
94-
start: '01/01/2009',
95-
finish: '01/05/2009',
96-
effortDriven: (i % 5 === 0)
97-
};
98-
}
99-
this.dataset = mockDataset;
100102
}
101103

102104
hookAllLoaderEvents() {
103-
this.loaderDataView.onDataLoading.subscribe((e, args) => {
104-
this.loading = true;
105-
});
106-
107-
this.loaderDataView.onDataLoaded.subscribe((e, args) => {
108-
for (let i = args.from; i <= args.to; i++) {
109-
this.gridObj.invalidateRow(i);
110-
}
111-
this.gridObj.updateRowCount();
112-
this.gridObj.render();
113-
this.loading = false;
114-
});
105+
if (this._eventHandler && this._eventHandler.subscribe && this.loaderDataView && this.loaderDataView.onDataLoading && this.loaderDataView.onDataLoaded) {
106+
this._eventHandler.subscribe(this.loaderDataView.onDataLoading, (e: Event, args: any) => {
107+
this.loading = true;
108+
});
109+
110+
this._eventHandler.subscribe(this.loaderDataView.onDataLoaded, (e: Event, args: any) => {
111+
if (args && this.gridObj && this.gridObj.invalidateRow && this.gridObj.updateRowCount && this.gridObj.render) {
112+
for (let i = args.from; i <= args.to; i++) {
113+
this.gridObj.invalidateRow(i);
114+
}
115+
this.gridObj.updateRowCount();
116+
this.gridObj.render();
117+
this.loading = false;
118+
}
119+
});
120+
}
115121
}
116122

117-
hookSearch() {
118-
$('#txtSearch').keyup((e) => {
119-
if (e.which === 13) {
120-
this.loaderDataView.setSearch(e.target.value);
121-
const vp = this.gridObj.getViewport();
122-
this.loaderDataView.ensureData(vp.top, vp.bottom);
123+
onSort(e, args) {
124+
if (this.gridObj && this.gridObj.getViewport && this.loaderDataView && this.loaderDataView.ensureData && this.loaderDataView.setSort) {
125+
const vp = this.gridObj.getViewport();
126+
if (args && args.sortCol && args.sortCol.field) {
127+
this.loaderDataView.setSort(args.sortCol.field, args.sortAsc ? 1 : -1);
123128
}
124-
});
125-
this.loaderDataView.setSearch($('#txtSearch').val());
129+
this.loaderDataView.ensureData(vp.top, vp.bottom);
130+
}
126131
}
127132

128-
onSort(e, args) {
129-
const vp = this.gridObj.getViewport();
130-
if (args && args.sortCol && args.sortCol.field) {
131-
this.loaderDataView.setSort(args.sortCol.field, args.sortAsc ? 1 : -1);
133+
onViewportChanged(e, args) {
134+
if (this.gridObj && this.gridObj.getViewport && this.loaderDataView && this.loaderDataView.ensureData) {
135+
const vp = this.gridObj.getViewport();
136+
this.loaderDataView.ensureData(vp.top, vp.bottom);
132137
}
133-
this.loaderDataView.ensureData(vp.top, vp.bottom);
134138
}
135139

136-
onViewportChanged(e, args) {
137-
const vp = this.gridObj.getViewport();
138-
this.loaderDataView.ensureData(vp.top, vp.bottom);
140+
searchChanged(newValue: string) {
141+
if (newValue && this.gridObj && this.gridObj.getViewport && this.loaderDataView && this.loaderDataView.ensureData && this.loaderDataView.setSearch) {
142+
const vp = this.gridObj.getViewport();
143+
this.loaderDataView.setSearch(newValue);
144+
this.loaderDataView.ensureData(vp.top, vp.bottom);
145+
}
139146
}
140147
}

src/app/modules/angular-slickgrid/components/angular-slickgrid.component.ts

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -211,13 +211,15 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy, OnIn
211211
this.gridOptions = this.mergeGridOptions(this.gridOptions);
212212
this.createBackendApiInternalPostProcessCallback(this.gridOptions);
213213

214-
if (this.gridOptions.enableGrouping) {
215-
this.extensionUtility.loadExtensionDynamically(ExtensionName.groupItemMetaProvider);
216-
this.groupItemMetadataProvider = new Slick.Data.GroupItemMetadataProvider();
217-
this.sharedService.groupItemMetadataProvider = this.groupItemMetadataProvider;
218-
this._dataView = new Slick.Data.DataView({ groupItemMetadataProvider: this.groupItemMetadataProvider });
219-
} else {
220-
this._dataView = new Slick.Data.DataView();
214+
if (!this.customDataView) {
215+
if (this.gridOptions.enableGrouping) {
216+
this.extensionUtility.loadExtensionDynamically(ExtensionName.groupItemMetaProvider);
217+
this.groupItemMetadataProvider = new Slick.Data.GroupItemMetadataProvider();
218+
this.sharedService.groupItemMetadataProvider = this.groupItemMetadataProvider;
219+
this._dataView = new Slick.Data.DataView({ groupItemMetadataProvider: this.groupItemMetadataProvider });
220+
} else {
221+
this._dataView = new Slick.Data.DataView();
222+
}
221223
}
222224

223225
// for convenience, we provide the property "editor" as an Angular-Slickgrid editor complex object
@@ -237,11 +239,8 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy, OnIn
237239
this.sharedService.visibleColumns = this._columnDefinitions;
238240
this.extensionService.createCheckboxPluginBeforeGridCreation(this._columnDefinitions, this.gridOptions);
239241

240-
if (this.gridOptions && this.customDataView) {
241-
this.grid = new Slick.Grid(`#${this.gridId}`, this.customDataView, this._columnDefinitions, this.gridOptions);
242-
} else {
243-
this.grid = new Slick.Grid(`#${this.gridId}`, this._dataView, this._columnDefinitions, this.gridOptions);
244-
}
242+
// build SlickGrid Grid, also user might optionally pass a custom dataview (e.g. remote model)
243+
this.grid = new Slick.Grid(`#${this.gridId}`, this.customDataView || this._dataView, this._columnDefinitions, this.gridOptions);
245244

246245
this.sharedService.dataView = this._dataView;
247246
this.sharedService.grid = this.grid;
@@ -251,12 +250,16 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy, OnIn
251250

252251
// emit the Grid & DataView object to make them available in parent component
253252
this.onGridCreated.emit(this.grid);
254-
this.onDataviewCreated.emit(this._dataView);
255253

254+
// initialize the SlickGrid grid
256255
this.grid.init();
257-
this._dataView.beginUpdate();
258-
this._dataView.setItems(this._dataset, this.gridOptions.datasetIdPropertyName);
259-
this._dataView.endUpdate();
256+
257+
if (!this.customDataView && (this._dataView && this._dataView.beginUpdate && this._dataView.setItems && this._dataView.endUpdate)) {
258+
this.onDataviewCreated.emit(this._dataView);
259+
this._dataView.beginUpdate();
260+
this._dataView.setItems(this._dataset, this.gridOptions.datasetIdPropertyName);
261+
this._dataView.endUpdate();
262+
}
260263

261264
// user might want to hide the header row on page load but still have `enableFiltering: true`
262265
// if that is the case, we need to hide the headerRow ONLY AFTER all filters got created & dataView exist
@@ -454,14 +457,16 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy, OnIn
454457
this.gridEventService.attachOnCellChange(grid, dataView);
455458
this.gridEventService.attachOnClick(grid, dataView);
456459

457-
this._eventHandler.subscribe(dataView.onRowCountChanged, (e: any, args: any) => {
458-
grid.updateRowCount();
459-
grid.render();
460-
});
461-
this._eventHandler.subscribe(dataView.onRowsChanged, (e: any, args: any) => {
462-
grid.invalidateRows(args.rows);
463-
grid.render();
464-
});
460+
if (dataView && grid) {
461+
this._eventHandler.subscribe(dataView.onRowCountChanged, (e: any, args: any) => {
462+
grid.updateRowCount();
463+
grid.render();
464+
});
465+
this._eventHandler.subscribe(dataView.onRowsChanged, (e: any, args: any) => {
466+
grid.invalidateRows(args.rows);
467+
grid.render();
468+
});
469+
}
465470

466471
// does the user have a colspan callback?
467472
if (gridOptions.colspanCallback) {

src/app/modules/angular-slickgrid/extensions/headerMenuExtension.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,13 @@ export class HeaderMenuExtension implements Extension {
159159
cols.push({ sortCol: args.column, sortAsc: (args.command === 'sort-asc') });
160160
if (this.sharedService.gridOptions.backendServiceApi) {
161161
this.sortService.onBackendSortChanged(e, { multiColumnSort: true, sortCols: cols, grid: this.sharedService.grid });
162-
} else {
162+
} else if (this.sharedService.dataView) {
163163
this.sortService.onLocalSortChanged(this.sharedService.grid, this.sharedService.dataView, cols);
164+
} else {
165+
// when using customDataView, we will simply send it as a onSort event with notify
166+
const isMultiSort = this.sharedService && this.sharedService.gridOptions && this.sharedService.gridOptions.multiColumnSort || false;
167+
const sortOutput = isMultiSort ? cols : cols[0];
168+
args.grid.onSort.notify(sortOutput);
164169
}
165170

166171
// update the this.sharedService.gridObj sortColumns array which will at the same add the visual sort icon(s) on the UI

0 commit comments

Comments
 (0)