Issue with re-render when a row is selected

Tags: #<Tag:0x00007f135c54fdf0> #<Tag:0x00007f135c54fcb0>

I have the following code where if I press the header row button, all the row takes the background with green color but when i select one row that is not on the initial view, the view at re-render goes to the initial one and did not maintain on my view.

afterOnCellMouseDown: function(event, coords) {
if (coords.row === -1) {
let newColumnStates = {…columnStates};
newColumnStates[coords.col] = !newColumnStates[coords.col];
setColumnStates(newColumnStates);
hotInstance.current.render();
}
},
cells: function(row, col, prop) {
if (rowStates[row]) {
cellProperties.renderer = function(instance, td, row, col, prop, value, cellProperties) {
Handsontable.renderers.TextRenderer.apply(this, arguments);
td.style.backgroundColor = ‘#a1d690’;
};
}
}

How can I solve it?

Hi @marcarandagil

Thank you for contacting us. Can you please share a code demo where the issue is replicable? There are some missing variables in the code you shared, and I’m not able to determine what the problem is.

That’s my React code where I fix the HandsonTable

useEffect(() => {
if (!hotInstance.current) {
// Inicializar Handsontable al montar el componente
hotInstance.current = new Handsontable(container.current, {
data: datasetValues,
colHeaders: function(col) {
const headerValue = titles[col];
const buttonStyle = columnStates[col] ? ‘’ : ‘background-color: #e6adad;’;
return <button style="${buttonStyle}">${headerValue}</button>;
},
columnHeaderHeight: 30,
rowHeaders: function(row) {
const headerValue = row + 1;
const buttonStyle = rowStates[row] ? ‘background-color: #a1d690;’ : ‘’;
return <button style="${buttonStyle}">${headerValue}</button>;
},
rowHeaderWidth: 75,
afterOnCellMouseDown: function(event, coords) {
if (coords.row === -1 && coords.col === -1) {
setColumnStates(Array(Object.keys(datasetData[1]).length).fill(true));
setRowStates(Array(Object.keys(datasetData).length).fill(false));
} else if (coords.row === -1) {
let newColumnStates = {…columnStates};
newColumnStates[coords.col] = !newColumnStates[coords.col];
setColumnStates(newColumnStates);
} else if (coords.col === -1) {
let newRowStates = {…rowStates};
newRowStates[coords.row] = !newRowStates[coords.row];
setRowStates(newRowStates);
}

                hotInstance.current.render();
            },
            cells: function(row, col, prop) {
                const cellProperties = {};
                if (!columnStates[col]) {
                    cellProperties.renderer = function(instance, td, row, col, prop, value, cellProperties) {
                        Handsontable.renderers.TextRenderer.apply(this, arguments);
                        td.style.backgroundColor = '#e6adad';
                    };
                } else if (rowStates[row]) {
                    cellProperties.renderer = function(instance, td, row, col, prop, value, cellProperties) {
                        Handsontable.renderers.TextRenderer.apply(this, arguments);
                        td.style.backgroundColor = '#a1d690';
                    };
                } else {
                    cellProperties.renderer = function(instance, td, row, col, prop, value, cellProperties) {
                        Handsontable.renderers.TextRenderer.apply(this, arguments);
                        td.style.backgroundColor = '';
                    };
                }
                return cellProperties;
            },
            afterRender: function(isForced) {
                // Selecciona el TH de la esquina si aún no tiene el botón
                var cornerHeader = document.querySelector('.ht_clone_top_left_corner .htCore > thead > tr > th');
                if (cornerHeader && !cornerHeader.querySelector('.corner-header-button')) {
                  cornerHeader.innerHTML = '';
                  var button = document.createElement('button');
                  button.textContent = 'CLEAR';
                  cornerHeader.appendChild(button);
                }
              },
            licenseKey: 'non-commercial-and-evaluation',
            type: 'numeric'
            // Otras opciones de configuración...
        });
    }

    // Función de limpieza al desmontar el componente
    return () => {
        if (hotInstance.current) {
            hotInstance.current.destroy();
            hotInstance.current = null;
        }
    };
}, );

Hi @marcarandagil

Can you please modify this example to match your implementation? https://jsfiddle.net/handsoncode/3ymg0n41/

I don’t know how edit correctly the page you send me but I upload a video from my application and you can see how it works and what is my problem

@marcarandagil

Thank you for the video, but unfortunately I can’t do much without replicable example. You can use other sandbox if you like, CodeSandbox or StackBlitz.

here it is

https://codesandbox.io/p/sandbox/try-7crpzr?file=%2Fsrc%2FFile.js%3A24%2C38

Hi @marcarandagil

Thank you for the example. I was able to narrow down what is causing this problem. It looks that your logic inside afterOnCellMouseDown hook is responsible for this behavior. It’s probably due to resetting the state of currently clicked row headers on each mouse down event. I would suggest to analyze this logic.

What I want is that when I select one row that is not at the first view, when I do the render, the view goes to the first one and not mantain at the view of the selected row. How can I do it?

@marcarandagil

I am not able to rewrite your logic for this hook, and it is responsible for this issue. I can suggest to try different approach instead of doing that with React state, but again, that might be your project’s requirement.

If that’s not the case, you can try similar approach to presented here, also using this hook: https://jsfiddle.net/handsoncode/ody7mw5q/

It will need adjusting to your project, but it should give you a general idea, how it can be done in a different way.