Question

Is there a way to show grand totals in Slickgrid with grouping?

I found following:

1) In documentation Implementing a totals row via a data provider. But then I can't use DataView and grouping features.

2) There is plugin for SlickGrid called Slickgrid totals plugin. But it doesn't allow to use grouping features.

Was it helpful?

Solution

  1. Add TotalsDataProvider function
function TotalsDataProvider(dataView, columns) {
  var totals = {};
  var totalsMetadata = {
  // Style the totals row differently.
    cssClasses: "totals",
    columns: {}
  };
  // Make the totals not editable.
  for (var i = 0; i < columns.length; i++) {
    totalsMetadata.columns[i] = { editor: null };
  }
  this.getLength = function() {
    return dataView.getLength() + 1;
  }
  this.getItem = function(index) {
    return (index < dataView.getLength()) ? dataView.getItem(index) : totals;
  };

  // Some group-functions from DataView
  this.setRefreshHints = function(hints) {
    return dataView.setRefreshHints(hints);
  };
  this.collapseGroup = function(varArgs) {
    return dataView.collapseGroup(varArgs);
  };
  this.expandGroup = function(varArgs) {
    return dataView.expandGroup(varArgs);
  };

  this.updateTotals = function() {
    var columnIdx = columns.length;
    while (columnIdx--) {
      var column = columns[columnIdx];
      if (!column.hasTotal) { // Just add in your column "hasTotal: true" 
        continue;
      }
      var total = 0;
      var i = dataView.getLength();
      while (i--) {
        total += (dataView.getItem(i)[column.field] || 0);
      }
      totals[column.field] = total;
    }
  };
  this.getItemMetadata = function(index) {
    return (index != dataView.getLength()) ? dataView.getItemMetadata(index) : totalsMetadata;
  };
  this.updateTotals();
}
  1. Add option "hasTotal: true" in your columns. For example:
var columns = [
        {id: "id", name: "Index", field: "id", hasTotal: true},
        {id: "title", name: "Title", field: "title"},
        {id: "duration", name: "Duration", field: "duration", hasTotal: true},
        {id: "%", name: "% Complete", field: "percentComplete", hasTotal: true},
        {id: "start", name: "Start", field: "start"},
        {id: "finish", name: "Finish", field: "finish"},
        {id: "effort-driven", name: "Effort Driven", field: "effortDriven"}
      ];
  1. Change grid variable and add dataProvider variable above:
//grid = new Slick.Grid("#myGrid", dataView, columns, options);
var dataProvider = new TotalsDataProvider(dataView, columns);
grid = new Slick.Grid("#myGrid", dataProvider, columns, options);
  1. Every time you change data (by filtering or by grid.onCellCange) you need update total data:
// The data has changed - recalculate the totals.
dataProvider.updateTotals(); 
// Rerender the totals row (last row).     
grid.invalidateRow(dataProvider.getLength() - 1);
grid.render();

OTHER TIPS

I found some workaround. The algorithm is as follows:

  1. Collect JSON data
  2. Calculate grand totals for needed columns
  3. Push extra row (array element) at the bottom of JSON data array, with additional param, for example, noGrouping:true
  4. Push data to DataView usingdataView.setItems(JSONDataArray)
  5. In slick.dataview.js in function addTotals, after line:

    g.collapsed = groupCollapsed ^ toggledGroups[g.groupingKey]; add:

    if(g.rows[0].noGrouping) {
      g.collapsed = true;
    }
    

    So the group of grand totals is always collapsed

  6. If needed, add some formatting in slick.groupitemmetadataprovider.js for function defaultGroupCellFormatter

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top