Retrieving a hidden header inside a sorted handson

2019-04-20 21:12发布

问题:

When using Handsontable, it seems hard to retrieve the header of a row from a contextual menu.

Consider the following data source:

var data = function () {
 return [["1212", "roman", "i", "ii", "iii"],
         ["3121", "numeric", 1, 2 ,3],
         ["4126", "alpha", 'a', 'b', 'c']];
};

It is possible to create a Handsontable instance that displays all of the data but the first two "columns", and that has a contextual menu as following:

// Settings to display all columns but the first two
var dataCols = []
for(var i=2; i<data()[0].length; i++) {
  dataCols.push({ data: i })
}

// Instance creation
var hot = new Handsontable(container, {
  data: data(),
  height: 396,
  colHeaders: true,
  rowHeaders: false,
  columns: dataCols,
  stretchH: 'all',
  columnSorting: true,
  contextMenu: {
    callback: function(key, options) {
      switch(key) {
      case 'header_pls':
        // TODO retrieve the "hidden header" from here    
        break;
      }
    },
    items: {
      "header_pls": {
        name: "Header please?"
      }
    }
  },
});

The options parameter from the context menu callback is made of two objects, start and end, both having a row and a col property.

Let's keep it simple and assume there will always be a single cell selected: start and end are the same object.

It is then possible to retrieve the header from the data source (and not the data bound to the instance) using Handsontable's method getSourceDataAtRow.

This could do the trick, but when the table has been sorted by clicking on a column header, the row number from the data source and the data bound to the instance are no longer the same.

Here is an example that shows what the problem is.

It is impossible to retrieve one of the two first elements of a row once the table has been sorted.

Did I miss somthing?

回答1:

I think your issue is boiled down to how to get the real (physical) index after sorting. Please correct me if I'm wrong because this answer revolves around that.

Here's what you need to know: when you use the built in sorter, Handson doesn't actually sort your data array. This is a default behavior which may or may not be useful to you. Regardless, from that point on every internal method uses what's called a "logical index" which is just the new sorted index. The internal methods then use a conversion from the logical to physical index when trying to access a data point.

In your case, you'd want to retrieve your physical index given your logical index so that you can correctly access the data. This can be done using a simple function:

physicalIndex = instance.sortIndex[logicalIndex][0];

Given this information you should be able to add some logic so that whenever you try to access the data, just make sure you use this transformed physical index; in my case I just check that instance.sortIndex is not undefined (which I think is the case before sorting) and every other time just assign this index since even without sorting, logicalIndex == physicalIndex.

Hope that helps!



回答2:

i've found that you can use a custom renderer to hide cells.

function customRenderer(instance, td, row, col) {
    Handsontable.renderers.TextRenderer.apply(this, arguments);
    if([0, 1].indexOf(col) > -1) {
      td.style.display =  "none";
    }
    return td;
}

With this you can get the data of the hidden columns with getDataAtCell because you use the original datasource in the displayed table. Here is the updated fiddle : https://jsfiddle.net/xartok/upc4mcd0/5/

There is another problem though, with the column headers...