Search code examples
javascriptreactjshandsontable

Styling nested rows conditionally in Handsontable


Using React wrapper for Handsontable. Data has nested child rows several levels deep.

Data looks like this:

[
  {
    category: "Category A",
    subCategory: null,
    subItem: null,
    value: "abc 123",
    __children: [
      {
        category: null,
        subCategory: "Sub Category 1",
        subItem: null,
        value: "xyz 456",
      },
      {
        category: null,
        subCategory: "Sub Category 2",
        subItem: null,
        value: "qwe 987",
        __children: [
          {
            category: null,
            subCategory: null,
            subItem: "Sub Item I",
            value: "asd 987",
          },
        ],
      },
    ],
  },
  {
    category: "Category B",
    subCategory: null,
    subItem: null,
    value: "abc 345",
    __children: null,
  },
]

Let's say I need everything under "Category A" to be green but not under "Category B". How can that be done?

I tried passing a cells function (row, col, prop) => {...} but that gives me just the index of the row and column. The row index changes depending on what categories are collapsed. So, I need to be able to style the entire row based on the value of category of the parent row.


Solution

  • It's quite hard to implement the feature since almost all configurations are based on row and col indexes, the only workaround I found is to add the color along the value and use a custom renderer to evaluate when there is metadata in the string, you'll need to prepare your data beforehand

    const data = [
        {
          category: "Category A",
          subCategory: null,
          subItem: null,
          value: "abc 123#color:green",
          __children: [
            {
              category: "#color:green",
              subCategory: "Sub Category 1#color:green",
              subItem: null,
              value: "xyz 456"
            },
            {
              category: null,
              subCategory: "Sub Category 2",
              subItem: null,
              value: "qwe 987",
              __children: [
                {
                  category: null,
                  subCategory: null,
                  subItem: "Sub Item I#color:green",
                  value: "asd 987"
                }
              ]
            }
          ]
        },
        {
          category: "Category B",
          subCategory: null,
          subItem: null,
          value: "abc 345",
          __children: null
        }
      ];
    
    ...
    
    const renderer = (instance, TD, row, col, prop, value, cellProperties) => {
      TD.innerHTML = "";
      if (value) {
        if (value.indexOf("#color:") >= 0) {
          const [realValue, color] = value.split("#color:");
          TD.style.backgroundColor = color;
          TD.innerHTML = realValue;
        } else {
          TD.innerHTML = value;
        }
      }
      return TD;
    };
    
    ...
    
          <HotTable
            data={data}
            colHeaders={true}
            rowHeaders={true}
            nestedRows={true}
            observeChanges
            renderer={renderer}
            licenseKey="non-commercial-and-evaluation"
          />
    

    You can see it working here https://codesandbox.io/s/handsontable-epbpi?file=/src/index.tsx