diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts
index 6ff16638a..8e5e4c56a 100644
--- a/src/app/app-routing.module.ts
+++ b/src/app/app-routing.module.ts
@@ -4,6 +4,7 @@ import { GridBasicComponent } from './examples/grid-basic.component';
import { GridClientSideComponent } from './examples/grid-clientside.component';
import { GridEditorComponent } from './examples/grid-editor.component';
import { GridFormatterComponent } from './examples/grid-formatter.component';
+import { GridGroupingComponent } from './examples/grid-grouping.component';
import { GridHeaderButtonComponent } from './examples/grid-headerbutton.component';
import { GridHeaderMenuComponent } from './examples/grid-headermenu.component';
import { GridLocalizationComponent } from './examples/grid-localization.component';
@@ -27,6 +28,7 @@ const routes: Routes = [
{ path: 'headermenu', component: GridHeaderMenuComponent },
{ path: 'gridgraphql', component: GridGraphqlComponent },
{ path: 'gridmenu', component: GridMenuComponent },
+ { path: 'grouping', component: GridGroupingComponent },
{ path: 'localization', component: GridLocalizationComponent },
{ path: 'clientside', component: GridClientSideComponent },
{ path: 'odata', component: GridOdataComponent },
diff --git a/src/app/app.component.html b/src/app/app.component.html
index 1d7669b6d..f7c907be3 100644
--- a/src/app/app.component.html
+++ b/src/app/app.component.html
@@ -67,6 +67,9 @@
13- Backend Server Custom Paging
+
+ 14- Grouping & Aggregator
+
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index c4cf4f8f5..3cad6fcf9 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -13,6 +13,7 @@ import { GridClientSideComponent } from './examples/grid-clientside.component';
import { GridEditorComponent } from './examples/grid-editor.component';
import { GridFormatterComponent } from './examples/grid-formatter.component';
import { GridGraphqlComponent } from './examples/grid-graphql.component';
+import { GridGroupingComponent } from './examples/grid-grouping.component';
import { GridHeaderButtonComponent } from './examples/grid-headerbutton.component';
import { GridHeaderMenuComponent } from './examples/grid-headermenu.component';
import { GridLocalizationComponent } from './examples/grid-localization.component';
@@ -63,6 +64,7 @@ export function appInitializerFactory(translate: TranslateService, injector: Inj
GridEditorComponent,
GridFormatterComponent,
GridGraphqlComponent,
+ GridGroupingComponent,
GridHeaderButtonComponent,
GridHeaderMenuComponent,
GridLocalizationComponent,
diff --git a/src/app/examples/grid-grouping.component.html b/src/app/examples/grid-grouping.component.html
new file mode 100644
index 000000000..6e48b355e
--- /dev/null
+++ b/src/app/examples/grid-grouping.component.html
@@ -0,0 +1,45 @@
+
+
+
{{title}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/app/examples/grid-grouping.component.ts b/src/app/examples/grid-grouping.component.ts
new file mode 100644
index 000000000..1646b7506
--- /dev/null
+++ b/src/app/examples/grid-grouping.component.ts
@@ -0,0 +1,221 @@
+import { Component, OnInit } from '@angular/core';
+import { Column, FieldType, Formatter, Formatters, GridOption, Editors } from './../modules/angular-slickgrid';
+
+// using external non-typed js libraries
+declare var Slick: any;
+
+// create my custom Formatter with the Formatter type
+const myCustomCheckmarkFormatter: Formatter = (row: number, cell: number, value: any, columnDef: Column, dataContext: any) =>
+ value ? `` : '';
+
+@Component({
+ templateUrl: './grid-grouping.component.html'
+})
+export class GridGroupingComponent implements OnInit {
+ title = 'Example 14: Grouping';
+ subTitle = `
+
+ - Fully dynamic and interactive multi-level grouping with filtering and aggregates over 50'000 items
+ - Each grouping level can have its own aggregates (over child rows, child groups, or all descendant rows)..
+
+ `;
+
+ columnDefinitions: Column[];
+ gridOptions: GridOption;
+ dataset: any[];
+ gridObj: any;
+ dataviewObj: any;
+ sortcol = 'title';
+ sortdir = 1;
+ percentCompleteThreshold = 0;
+ prevPercentCompleteThreshold = 0;
+
+ ngOnInit(): void {
+ this.columnDefinitions = [
+ { id: 'sel', name: '#', field: 'num', width: 40, maxWidth: 70, resizable: true, selectable: false, focusable: false },
+ { id: 'title', name: 'Title', field: 'title', width: 70, minWidth: 50, cssClass: 'cell-title', sortable: true, editor: Editors.text },
+ { id: 'duration', name: 'Duration', field: 'duration', width: 70, sortable: true, groupTotalsFormatter: this.sumTotalsFormatter },
+ { id: '%', name: '% Complete', field: 'percentComplete', width: 80, formatter: Formatters.percentCompleteBar, sortable: true, groupTotalsFormatter: this.avgTotalsFormatter },
+ { id: 'start', name: 'Start', field: 'start', minWidth: 60, sortable: true, formatter: Formatters.dateIso },
+ { id: 'finish', name: 'Finish', field: 'finish', minWidth: 60, sortable: true, formatter: Formatters.dateIso },
+ { id: 'cost', name: 'Cost', field: 'cost', width: 90, sortable: true, groupTotalsFormatter: this.sumTotalsFormatter },
+ { id: 'effort-driven', name: 'Effort Driven', width: 80, minWidth: 20, maxWidth: 80, cssClass: 'cell-effort-driven', field: 'effortDriven', formatter: Formatters.checkmark, sortable: true }
+ ];
+ this.gridOptions = {
+ autoResize: {
+ containerId: 'demo-container',
+ sidePadding: 15
+ },
+ enableGrouping: true
+ };
+
+ this.loadData(500);
+ }
+
+ loadData(rowCount: number) {
+ // mock a dataset
+ this.dataset = [];
+ for (let i = 0; i < rowCount; i++) {
+ const randomYear = 2000 + Math.floor(Math.random() * 10);
+ const randomMonth = Math.floor(Math.random() * 11);
+ const randomDay = Math.floor((Math.random() * 29));
+ const randomPercent = Math.round(Math.random() * 100);
+
+ this.dataset[i] = {
+ id: 'id_' + i,
+ num: i,
+ title: 'Task ' + i,
+ duration: Math.round(Math.random() * 100) + '',
+ percentComplete: randomPercent,
+ percentCompleteNumber: randomPercent,
+ start: new Date(randomYear, randomMonth, randomDay),
+ finish: new Date(randomYear, (randomMonth + 1), randomDay),
+ cost: Math.round(Math.random() * 10000) / 100,
+ effortDriven: (i % 5 === 0)
+ };
+ }
+ }
+
+ gridReady(grid) {
+ this.gridObj = grid;
+ }
+
+ dataviewReady(dataview) {
+ this.dataviewObj = dataview;
+ }
+
+ clearGrouping() {
+ this.dataviewObj.setGrouping([]);
+ }
+
+ collapseAllGroups() {
+ this.dataviewObj.collapseAllGroups();
+ }
+
+ expandAllGroups() {
+ this.dataviewObj.expandAllGroups();
+ }
+
+ avgTotalsFormatter(totals, columnDef) {
+ const val = totals.avg && totals.avg[columnDef.field];
+ if (val != null) {
+ return 'avg: ' + Math.round(val) + '%';
+ }
+ return '';
+ }
+ sumTotalsFormatter(totals, columnDef) {
+ const val = totals.sum && totals.sum[columnDef.field];
+ if (val != null) {
+ return 'total: ' + ((Math.round(parseFloat(val) * 100) / 100));
+ }
+ return '';
+ }
+ myFilter(item, args) {
+ return item['percentComplete'] >= args.percentComplete;
+ }
+ percentCompleteSort(a, b) {
+ return a['percentComplete'] - b['percentComplete'];
+ }
+ comparer(a: any, b: any) {
+ const x = a[this.sortcol], y = b[this.sortcol];
+ return (x === y ? 0 : (x > y ? 1 : -1));
+ }
+ groupByDuration() {
+ this.dataviewObj.setGrouping({
+ getter: 'duration',
+ formatter: (g) => {
+ return `Duration: ${g.value} (${g.count} items)`;
+ },
+ aggregators: [
+ new Slick.Data.Aggregators.Avg('percentComplete'),
+ new Slick.Data.Aggregators.Sum('cost')
+ ],
+ aggregateCollapsed: false,
+ lazyTotalsCalculation: true
+ });
+ }
+ groupByDurationOrderByCount(aggregateCollapsed) {
+ this.dataviewObj.setGrouping({
+ getter: 'duration',
+ formatter: (g) => {
+ return `Duration: ${g.value} (${g.count} items)`;
+ },
+ comparer: (a, b) => {
+ return a.count - b.count;
+ },
+ aggregators: [
+ new Slick.Data.Aggregators.Avg('percentComplete'),
+ new Slick.Data.Aggregators.Sum('cost')
+ ],
+ aggregateCollapsed,
+ lazyTotalsCalculation: true
+ });
+ }
+ groupByDurationEffortDriven() {
+ this.dataviewObj.setGrouping([
+ {
+ getter: 'duration',
+ formatter: (g) => {
+ return `Duration: ${g.value} (${g.count} items)`;
+ },
+ aggregators: [
+ new Slick.Data.Aggregators.Sum('duration'),
+ new Slick.Data.Aggregators.Sum('cost')
+ ],
+ aggregateCollapsed: true,
+ lazyTotalsCalculation: true
+ },
+ {
+ getter: 'effortDriven',
+ formatter: (g) => {
+ return `Effort-Driven: ${(g.value ? 'True' : 'False')} (${g.count} items)`;
+ },
+ aggregators: [
+ new Slick.Data.Aggregators.Avg('percentComplete'),
+ new Slick.Data.Aggregators.Sum('cost')
+ ],
+ collapsed: true,
+ lazyTotalsCalculation: true
+ }
+ ]);
+ }
+ groupByDurationEffortDrivenPercent() {
+ this.dataviewObj.setGrouping([
+ {
+ getter: 'duration',
+ formatter: (g) => {
+ return `Duration: ${g.value} (${g.count} items)`;
+ },
+ aggregators: [
+ new Slick.Data.Aggregators.Sum('duration'),
+ new Slick.Data.Aggregators.Sum('cost')
+ ],
+ aggregateCollapsed: true,
+ lazyTotalsCalculation: true
+ },
+ {
+ getter: 'effortDriven',
+ formatter: (g) => {
+ return `Effort-Driven: ${(g.value ? 'True' : 'False')} (${g.count} items)`;
+ },
+ aggregators: [
+ new Slick.Data.Aggregators.Sum('duration'),
+ new Slick.Data.Aggregators.Sum('cost')
+ ],
+ lazyTotalsCalculation: true
+ },
+ {
+ getter: 'percentComplete',
+ formatter: (g) => {
+ return `% Complete: ${g.value} (${g.count} items)`;
+ },
+ aggregators: [
+ new Slick.Data.Aggregators.Avg('percentComplete')
+ ],
+ aggregateCollapsed: true,
+ collapsed: true,
+ lazyTotalsCalculation: true
+ }
+ ]);
+ }
+}
diff --git a/src/app/modules/angular-slickgrid/components/angular-slickgrid.component.ts b/src/app/modules/angular-slickgrid/components/angular-slickgrid.component.ts
index 190ad3163..9f9b005a0 100644
--- a/src/app/modules/angular-slickgrid/components/angular-slickgrid.component.ts
+++ b/src/app/modules/angular-slickgrid/components/angular-slickgrid.component.ts
@@ -6,6 +6,7 @@ import 'slickgrid/slick.core';
import 'slickgrid/slick.dataview';
import 'slickgrid/slick.grid';
import 'slickgrid/slick.dataview';
+import 'slickgrid/slick.groupitemmetadataprovider.js';
import 'slickgrid/controls/slick.columnpicker';
import 'slickgrid/controls/slick.gridmenu';
import 'slickgrid/controls/slick.pager';
@@ -60,6 +61,7 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy, OnIn
gridHeightString: string;
gridWidthString: string;
groupingDefinition: any = {};
+ groupItemMetadataProvider: any;
showPagination = false;
isGridInitialized = false;
@@ -150,11 +152,23 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy, OnIn
this.gridOptions = this.mergeGridOptions(this.gridOptions);
this.createBackendApiInternalPostProcessCallback(this.gridOptions);
- this._dataView = new Slick.Data.DataView();
+ if (this.gridOptions.enableGrouping) {
+ this.groupItemMetadataProvider = new Slick.Data.GroupItemMetadataProvider();
+ this.sharedService.groupItemMetadataProvider = this.groupItemMetadataProvider;
+ this._dataView = new Slick.Data.DataView({
+ groupItemMetadataProvider: this.groupItemMetadataProvider,
+ inlineFilters: true
+ });
+ } else {
+ this._dataView = new Slick.Data.DataView();
+ }
this.controlAndPluginService.createPluginBeforeGridCreation(this._columnDefinitions, this.gridOptions);
this.grid = new Slick.Grid(`#${this.gridId}`, this._dataView, this._columnDefinitions, this.gridOptions);
- this.controlAndPluginService.attachDifferentControlOrPlugins(this.grid, this._columnDefinitions, this.gridOptions, this._dataView);
+ // pass all necessary options to the shared service
+ this.sharedService.init(this.grid, this._dataView, this.gridOptions, this._columnDefinitions);
+
+ this.controlAndPluginService.attachDifferentControlOrPlugins();
this.attachDifferentHooks(this.grid, this.gridOptions, this._dataView);
// emit the Grid & DataView object to make them available in parent component
@@ -166,9 +180,6 @@ export class AngularSlickgridComponent implements AfterViewInit, OnDestroy, OnIn
this._dataView.setItems(this._dataset, this.gridOptions.datasetIdPropertyName);
this._dataView.endUpdate();
- // pass all necessary options to the shared service
- this.sharedService.init(this.grid, this._dataView, this.gridOptions, this._columnDefinitions);
-
// attach resize ONLY after the dataView is ready
this.attachResizeHook(this.grid, this.gridOptions);
diff --git a/src/app/modules/angular-slickgrid/models/column.interface.ts b/src/app/modules/angular-slickgrid/models/column.interface.ts
index fc5c00f6c..6d0668300 100644
--- a/src/app/modules/angular-slickgrid/models/column.interface.ts
+++ b/src/app/modules/angular-slickgrid/models/column.interface.ts
@@ -2,6 +2,7 @@ import { ColumnFilter } from './columnFilter.interface';
import { Editor } from './editor.interface';
import { FieldType } from './fieldType';
import { Formatter } from './formatter.interface';
+import { GroupFormatter } from './groupFormatter.interface';
import { HeaderButtonItem } from './headerButtonItem.interface';
import { HeaderMenuItem } from './headerMenuItem.interface';
import { OnEventArgs } from './onEventArgs.interface';
@@ -73,9 +74,12 @@ export interface Column {
/** are we allowed to focus on the column? */
focusable?: boolean;
- /** Custom Sorter function that can be provided to the column */
+ /** Formatter function that can be used to change and format certain column(s) in the grid */
formatter?: Formatter;
+ /** Group Totals Formatter function that can be used to add grouping totals in the grid */
+ groupTotalsFormatter?: GroupFormatter;
+
/** Options that can be provide to the Header Menu Plugin */
header?: {
/** list of Buttons to show in the header */
diff --git a/src/app/modules/angular-slickgrid/models/gridOption.interface.ts b/src/app/modules/angular-slickgrid/models/gridOption.interface.ts
index 6131afa14..b9deb4af0 100644
--- a/src/app/modules/angular-slickgrid/models/gridOption.interface.ts
+++ b/src/app/modules/angular-slickgrid/models/gridOption.interface.ts
@@ -91,6 +91,9 @@ export interface GridOption {
/** Do we want to enable the Export to File? (if Yes, it will show up in the Grid Menu) */
enableExport?: boolean;
+ /** Defaults to false, do we want to enable the Grouping & Aggregator? */
+ enableGrouping?: boolean;
+
/** Defaults to false, which leads to all Formatters of the grid being evaluated on export. You can also override a column by changing the propery on the column itself */
exportWithFormatter?: boolean;
diff --git a/src/app/modules/angular-slickgrid/models/groupFormatter.interface.ts b/src/app/modules/angular-slickgrid/models/groupFormatter.interface.ts
new file mode 100644
index 000000000..a8ee46f4d
--- /dev/null
+++ b/src/app/modules/angular-slickgrid/models/groupFormatter.interface.ts
@@ -0,0 +1,3 @@
+import { Column } from './column.interface';
+
+export type GroupFormatter = (totals: any, columnDef: Column) => string;
diff --git a/src/app/modules/angular-slickgrid/models/index.ts b/src/app/modules/angular-slickgrid/models/index.ts
index c72eace23..ab07d9f78 100644
--- a/src/app/modules/angular-slickgrid/models/index.ts
+++ b/src/app/modules/angular-slickgrid/models/index.ts
@@ -35,6 +35,7 @@ export * from './graphqlPaginationOption.interface';
export * from './graphqlResult.interface';
export * from './graphqlServiceOption.interface';
export * from './graphqlSortingOption.interface';
+export * from './groupFormatter.interface';
export * from './customGridMenu.interface';
export * from './gridMenu.interface';
export * from './gridOption.interface';
diff --git a/src/app/modules/angular-slickgrid/services/controlAndPlugin.service.ts b/src/app/modules/angular-slickgrid/services/controlAndPlugin.service.ts
index 00a087394..fc515c5ae 100644
--- a/src/app/modules/angular-slickgrid/services/controlAndPlugin.service.ts
+++ b/src/app/modules/angular-slickgrid/services/controlAndPlugin.service.ts
@@ -16,6 +16,7 @@ import {
} from './../models/index';
import { TranslateService } from '@ngx-translate/core';
import { castToPromise } from './../services/utilities';
+import { SharedService } from './shared.service';
// using external non-typed js libraries
declare var Slick: any;
@@ -38,7 +39,7 @@ export class ControlAndPluginService {
gridMenuControl: any;
rowSelectionPlugin: any;
- constructor(private exportService: ExportService, private filterService: FilterService, private translate: TranslateService) { }
+ constructor(private exportService: ExportService, private filterService: FilterService, private sharedService: SharedService, private translate: TranslateService) { }
/**
* Attach/Create different Controls or Plugins after the Grid is created
@@ -47,72 +48,78 @@ export class ControlAndPluginService {
* @param options
* @param dataView
*/
- attachDifferentControlOrPlugins(grid: any, columnDefinitions: Column[], options: GridOption, dataView: any) {
- this._grid = grid;
- this._gridOptions = options;
- this._dataView = dataView;
- this._columnDefinitions = columnDefinitions;
- this.visibleColumns = columnDefinitions;
-
- if (options.enableColumnPicker) {
- this.columnPickerControl = this.createColumnPicker(grid, columnDefinitions, options);
+ attachDifferentControlOrPlugins() {
+ this._grid = this.sharedService.grid;
+ this._gridOptions = this.sharedService.gridOptions;
+ this._dataView = this.sharedService.dataView;
+ this._columnDefinitions = this.sharedService.columnDefinitions;
+ this.visibleColumns = this.sharedService.columnDefinitions;
+
+ if (this._gridOptions.enableColumnPicker) {
+ this.columnPickerControl = this.createColumnPicker(this._grid, this._columnDefinitions, this._gridOptions);
}
- if (options.enableGridMenu) {
- this.gridMenuControl = this.createGridMenu(grid, columnDefinitions, options);
+ if (this._gridOptions.enableGridMenu) {
+ this.gridMenuControl = this.createGridMenu(this._grid, this._columnDefinitions, this._gridOptions);
}
- if (options.enableAutoTooltip) {
- this.autoTooltipPlugin = new Slick.AutoTooltips(options.autoTooltipOptions || {});
- grid.registerPlugin(this.autoTooltipPlugin);
+ if (this._gridOptions.enableAutoTooltip) {
+ this.autoTooltipPlugin = new Slick.AutoTooltips(this._gridOptions.autoTooltipOptions || {});
+ this._grid.registerPlugin(this.autoTooltipPlugin);
}
- if (options.enableCheckboxSelector) {
+ // register the group item metadata provider to add expand/collapse group handlers
+ if (this._gridOptions.enableGrouping) {
+ const groupItemMetaProvider = this.sharedService.groupItemMetadataProvider || {};
+ this._grid.registerPlugin(groupItemMetaProvider);
+ }
+
+ if (this._gridOptions.enableCheckboxSelector) {
// when enabling the Checkbox Selector Plugin, we need to also watch onClick events to perform certain actions
// the selector column has to be create BEFORE the grid (else it behaves oddly), but we can only watch grid events AFTER the grid is created
- grid.registerPlugin(this.checkboxSelectorPlugin);
+ this._grid.registerPlugin(this.checkboxSelectorPlugin);
// this also requires the Row Selection Model to be registered as well
if (!this.rowSelectionPlugin) {
- this.rowSelectionPlugin = new Slick.RowSelectionModel(options.rowSelectionOptions || {});
- grid.setSelectionModel(this.rowSelectionPlugin);
+ this.rowSelectionPlugin = new Slick.RowSelectionModel(this._gridOptions.rowSelectionOptions || {});
+ this._grid.setSelectionModel(this.rowSelectionPlugin);
}
}
- if (options.enableRowSelection) {
- this.rowSelectionPlugin = new Slick.RowSelectionModel(options.rowSelectionOptions || {});
- grid.setSelectionModel(this.rowSelectionPlugin);
+ if (this._gridOptions.enableRowSelection) {
+ this.rowSelectionPlugin = new Slick.RowSelectionModel(this._gridOptions.rowSelectionOptions || {});
+ this._grid.setSelectionModel(this.rowSelectionPlugin);
}
- if (options.enableHeaderButton) {
- this.headerButtonsPlugin = new Slick.Plugins.HeaderButtons(options.headerButton || {});
- grid.registerPlugin(this.headerButtonsPlugin);
+ if (this._gridOptions.enableHeaderButton) {
+ this.headerButtonsPlugin = new Slick.Plugins.HeaderButtons(this._gridOptions.headerButton || {});
+ this._grid.registerPlugin(this.headerButtonsPlugin);
this.headerButtonsPlugin.onCommand.subscribe((e: Event, args: HeaderButtonOnCommandArgs) => {
- if (options.headerButton && typeof options.headerButton.onCommand === 'function') {
- options.headerButton.onCommand(e, args);
+ if (this._gridOptions.headerButton && typeof this._gridOptions.headerButton.onCommand === 'function') {
+ this._gridOptions.headerButton.onCommand(e, args);
}
});
}
- if (options.enableHeaderMenu) {
- const headerMenuOptions = options.headerMenu || {};
+ if (this._gridOptions.enableHeaderMenu) {
+ const headerMenuOptions = this._gridOptions.headerMenu || {};
headerMenuOptions.minWidth = headerMenuOptions.minWidth || 140;
headerMenuOptions.autoAlignOffset = headerMenuOptions.autoAlignOffset || 12;
this.headerMenuPlugin = new Slick.Plugins.HeaderMenu(headerMenuOptions);
- grid.registerPlugin(this.headerMenuPlugin);
+ this._grid.registerPlugin(this.headerMenuPlugin);
this.headerMenuPlugin.onCommand.subscribe((e: Event, args: HeaderMenuOnCommandArgs) => {
- if (options.headerMenu && typeof options.headerMenu.onCommand === 'function') {
- options.headerMenu.onCommand(e, args);
+ if (this._gridOptions.headerMenu && typeof this._gridOptions.headerMenu.onCommand === 'function') {
+ this._gridOptions.headerMenu.onCommand(e, args);
}
});
this.headerMenuPlugin.onCommand.subscribe((e: Event, args: HeaderMenuOnBeforeMenuShowArgs) => {
- if (options.headerMenu && typeof options.headerMenu.onBeforeMenuShow === 'function') {
- options.headerMenu.onBeforeMenuShow(e, args);
+ if (this._gridOptions.headerMenu && typeof this._gridOptions.headerMenu.onBeforeMenuShow === 'function') {
+ this._gridOptions.headerMenu.onBeforeMenuShow(e, args);
}
});
}
- if (options.registerPlugins !== undefined) {
- if (Array.isArray(options.registerPlugins)) {
- options.registerPlugins.forEach((plugin) => {
- grid.registerPlugin(plugin);
+ if (this._gridOptions.registerPlugins !== undefined) {
+ if (Array.isArray(this._gridOptions.registerPlugins)) {
+ this._gridOptions.registerPlugins.forEach((plugin) => {
+ this._grid.registerPlugin(plugin);
});
} else {
- grid.registerPlugin(options.registerPlugins);
+ this._grid.registerPlugin(this._gridOptions.registerPlugins);
}
}
}
diff --git a/src/app/modules/angular-slickgrid/services/shared.service.ts b/src/app/modules/angular-slickgrid/services/shared.service.ts
index d5f689b98..ffda4eb5f 100644
--- a/src/app/modules/angular-slickgrid/services/shared.service.ts
+++ b/src/app/modules/angular-slickgrid/services/shared.service.ts
@@ -5,6 +5,7 @@ export class SharedService {
grid: any;
gridOptions: GridOption;
columnDefinitions: Column[];
+ groupItemMetadataProvider: any;
init(grid: any, dataView: any, gridOptions: GridOption, columnDefinitions: Column[]) {
this.grid = grid;
diff --git a/src/app/modules/angular-slickgrid/styles/_variables.scss b/src/app/modules/angular-slickgrid/styles/_variables.scss
index 11b39494f..b5cd56624 100644
--- a/src/app/modules/angular-slickgrid/styles/_variables.scss
+++ b/src/app/modules/angular-slickgrid/styles/_variables.scss
@@ -72,6 +72,9 @@ $header-scroll-width-to-remove: 16px !default; //
/* icon font is using Font-Awesome by default but could be changed to any other icon package like Glyphicons, ... */
$icon-font-family: "FontAwesome" !default; // or Glyphicons Halflings */
$icon-font-size: 14px !default;
+$icon-group-expanded: "\f147" !default;
+$icon-group-collapsed: "\f196" !default;
+$icon-group-font-size: $icon-font-size !default;
$icon-sort-asc: "\f0d8" !default;
$icon-sort-desc: "\f0d7" !default;
$icon-sort-color: rgb(76, 128, 190) !default;
diff --git a/src/app/modules/angular-slickgrid/styles/slick-default-theme.scss b/src/app/modules/angular-slickgrid/styles/slick-default-theme.scss
index 2d467eb2b..3bca4b894 100644
--- a/src/app/modules/angular-slickgrid/styles/slick-default-theme.scss
+++ b/src/app/modules/angular-slickgrid/styles/slick-default-theme.scss
@@ -138,11 +138,17 @@
margin-right: 5px;
&.expanded:before {
- content: "\f196";
+ content: $icon-group-expanded;
+ font-family: $icon-font-family;
+ font-size: $icon-group-font-size;
+ cursor: pointer;
}
&.collapsed:before {
- content: "\f147";
+ content: $icon-group-collapsed;
+ font-family: $icon-font-family;
+ font-size: $icon-group-font-size;
+ cursor: pointer;
}
}