Collapsible rows State Save Option

Tags: #<Tag:0x00007f0b10d81a18> #<Tag:0x00007f0b10d818d8>

Hi Team,

We using Handsontable in Angular. We have multiple Nested rows in which we want to maintain the collapsible state. For example : if we have 4 Nested rows and the user want to Collapse the first nested row and keep the other Nested rows expanded and it state should be maintained even if we update the settings. Kindly let us know if we are able to get the details of collapsible state, store it and then update the handsontable settings with the Stored State.

Jsfiddle - Handsontable example - JSFiddle - Code Playground

Regards,
Vijay V

Hi @vijayvelchamy.v

There are no official methods to collapse and expand parent rows. However, you can try to use the collapsingUI. It allows to:

  • collapse a section of rows for a single-parent (here you need to pass row parent index)
  • expand a section of rows for a single-parent (here you need to pass row parent index)
  • collapse all parents
  • expand all parents

Here’s a demo https://jsfiddle.net/handsoncode/gceqrLd2/

So in your case, when you update the settings you would need to collapse certain sections again (as when you repload the data the parents expand).

Hi @aleksandra_budnik ,

Thanks for the response. If we click on the (+) Expand button of a nested row we need a hook to store the state of the particular Nested Row and then when we renavigate from another page, we have to apply the stored state that particular Nested Row is expanded. We want this action to be done dynamically as our row numbers may change for the fields. The above solution is static. Kindly let us know if we are able to achieve this.

the above solution CollapsingUI.CollapseChildren(6) is not available for our version Handonstable 7.

Regards,
Vijay V

@vijayvelchamy.v

That would be hard to propose changes/methods for the Handsontable v7. We are now on v13.x and version 7 is already 3.5+ years old.

If I may ask, did you have any issues while updating to a newer version? Due to security reasons, we recommend updating to the newest version as it appears. Especially for Clients that have a lower version that v10 as for this version we fixed one important vulnerability (ref: SNYK).

Also in v8.0.0 we fixed more than 150 issues related to indexes. That touches nearly every plugin that we have. Ref: Release notes for v8.0.0.

Hi @aleksandra_budnik ,

For Version 13, Can you please suggest solution for the below question.

If we click on the (+) Expand button of a nested row we need a hook to store the state of the particular Nested Row and then when we renavigate from another page, we have to apply the stored state that particular Nested Row is expanded. We want this action to be done dynamically as our row numbers may change for the fields. The above solution is static. Kindly let us know if we are able to achieve this

Regards,
Vijay V

The nestedRows plugin does not have a dedicated hook yet. However, we have a partial workaround for developers who are using one-level nesting. In this case you can use a JS native mouseup events on the +/- element. Here’ s a demo https://jsfiddle.net/h365gd9t/3/.

The code is

document.body.addEventListener('mouseup', function(e){
  if(e.target.classList[0] == 'ht_nestingButton'){
  	  console.log(e.target.parentNode.children[0].innerText)
  }
})

as you see we use a certain node check, which works only for the 1st levels of children. If you would have children for children rows, you would need to adjust the logic.

In this example, we log the header name. If you use the option rowHeaders: true your index of the row would be parseInt(e.target.parentNode.children[0].innerText) - 1. Based on the row index you can call the getDataAtCell() method to get the data from the row.

Hey @vijayvelchamy.v

Do you need any more feedback here or can we close the thread?

You can save the collapsed rows index in localStorage or database according to your needs.
You need to write logic in afterMouseDownOnCell and check if user clicked on parentRow. or you can bind the logic to ( +/- ) button of handsontable.

const afterMouseDownOnCell = (event: any, coords: CellCoords) => {
    if (hotRef !== null && hotRef.current) {
      let nestedRowPlug = hotRef.current.hotInstance!.getPlugin(
        "nestedRows"
      ) as any;
      let clickedVal = hotRef.current.hotInstance!.getDataAtCell(coords.row, 0);

      let isGroup =
        (nestedRowPlug.dataManager.data as []).findIndex(
          (d: any, indx) => d.id === clickedVal
        ) >= 0;

      if (!isGroup) {
        return;
      }

      let indexOfClickedRow = (
        nestedRowPlug.dataManager.cache.rows as []
      ).findIndex((d: any, indx) => d.id === clickedVal);

      let isCollapsed = (
        nestedRowPlug.collapsingUI.collapsedRows as number[]
      ).includes(indexOfClickedRow);

      let localStorageCollapsedRows: number[] = JSON.parse(
        localStorage.getItem(
          `gridCollapsedRows`
        ) || "[]"
      );

      let collapsedRowsToUpdate = localStorageCollapsedRows.filter(
        (rIndex) => rIndex !== indexOfClickedRow
      );

      if (isCollapsed) {
        nestedRowPlug.collapsingUI.expandChildren(indexOfClickedRow);
      } else {
        nestedRowPlug.collapsingUI.collapseChildren(indexOfClickedRow);
        collapsedRowsToUpdate = [...collapsedRowsToUpdate, indexOfClickedRow];
      }
      localStorage.setItem(
        `gridCollapsedRows`,
        JSON.stringify(collapsedRowsToUpdate)
      );

      setTimeout(() => {
        hotRef.current?.hotInstance?.render();
      }, 0);
    }
  };

After this you can get those values and update grid whenever its loaded or settings are updated. For me I used these settings only when grid is loaded first time.

let localStorageCollapsedRows: number[] = JSON.parse(
          localStorage.getItem(
            `gridCollapsedRows`
          ) || "[]"
        );

        localStorageCollapsedRows.forEach((rIndex) => {
          if (
            nestedRowPlug &&
            nestedRowPlug.isPluginsReady &&
            nestedRowPlug.dataManager &&
            nestedRowPlug.dataManager.cache &&
            nestedRowPlug.dataManager.cache.rows[rIndex] &&
            nestedRowPlug.dataManager.cache.rows[rIndex].hasOwnProperty(
              "__children"
            )
          )
            nestedRowPlug.collapsingUI.collapseChildren(rIndex);
        });

        hotRef.current?.hotInstance?.render();