afterChange null row values

Tags: #<Tag:0x00007efc6bbe7468> #<Tag:0x00007efc6bbe6cc0>

Hello,

We recently were paged by an error that appears to be coming from Handsontable, and it looks like the row value from the changes object returned by afterChange is either null or undefined. We have checks in place to ensure that the source is not loadData and that the changes array is not null, so I am confused as to how we could enter a state where the source is not “loadData”, the changes object is not null and somehow a change within the changes array contains a null or undefined row value.

Has anyone else encountered this or is anyone aware of a situation that might cause a null row value in an otherwise valid changes object?

Here is the TypeError we are getting:
Cannot read properties of undefined (reading 'parent_id')

For reference, here is our afterChange implementation (please see the comment pointing out the line of the error):

 const afterChange = (changes, source) => {
        if (!source.includes("loadData") && changes) {
            if (hotComponentRef) {
                if (typeof props.updateFormSettingsDispatch === "function") {
                    // if it's on allocation tab, extra action is required to update the totals
                    if (isAllocationTargetConfigTab(props.strategicTargetTab)) {
                        // changes: [[row, rowProp, oldVal, newVal],...]
                        let invalidCount = 0;
                        changes.forEach((change) => {
                            const [row, col, oldVal, newVal] = change;
                            const tableData = tableSettings["data"];
                            const totalSumRowIndex = tableData.length - 1;
                            if (validateCellInput(newVal)) {
                                invalidCount++;
                            }

                            // moving totalCandidates into useMemo
                            // const totalCandidates = findTotalCandidates(tableData);
                            if (col > 1 && oldVal !== newVal) {
                                let columnValues = hotComponentRef.current.hotInstance.getData(
                                    0,
                                    col,
                                    totalSumRowIndex,
                                    col,
                                );

                                // if parent_id !== null, it should update the total of the parent asset class and the total.
                                // otherwise it should be an asset class, just update the total.

                               // Handsontable error triggers in the line below: 

                                if (tableData[row]["parent_id"] != null) {
                                    const parentIndex = findParentRowIndex(tableData, row);
                                    const children = getChildren(tableData, parentIndex);
                                    let [first, last] = findFirstAndLastIndex(children);
                                    // const currentData = hotComponentRef.current.hotInstance.getData();

                                    // getData(row, column, row2, column2)
                                    const subAssetValues = hotComponentRef.current.hotInstance.getData(
                                        first,
                                        col,
                                        last,
                                        col,
                                    );
                                    // calculate sum of children row at col
                                    const subAssetSum = calculateSum(subAssetValues);

                                    // replace the cell value at (parentIndex, col) with calculated sum
                                    hotComponentRef.current.hotInstance.setDataAtRowProp(parentIndex, col, subAssetSum);

                                    // replace the columnValue at parentIndex of columnValues
                                    columnValues[parentIndex] = subAssetSum;
                                } else {
                                    // if parent_id === null, then skip and just update the total
                                }

                                // filter out only total candidates
                                const totalCandidateValues = columnValues.filter((value, i) =>
                                    totalCandidates.includes(i),
                                );

                                // once the sum of asset classes gets updated, we should also update the column total.
                                // calculate sum of sum candidates row at col
                                const total = calculateSum(totalCandidateValues);

                                // replace the cell value at (parentIndex, col) with calculated sum
                                hotComponentRef.current.hotInstance.setDataAtRowProp(totalSumRowIndex, col, total);
                            }
                        });
                        if (invalidCount === 0) {
                            setInvalidInputError(false);
                        }
                    }
                    handleFormUpdate(duration);
                }
            } else {
                console.warn("hotComponentRef was null.");
            }
        }
    };

Thank you!

Hi @george1

Sorry for keeping you waiting. I totally missed the notification.

I am not sure if I got the requirement correctly. Here’s a small demo that I prepared using the latest version of Handsontable and React: https://jsfiddle.net/5ag8Lvok/

We call the changes (other than those from the loadData execution) and a getData() core method to check if that is correctly applied.

Could you guide me on what the next step would be to get the same result as you have? There are some variables that I’d need to know to prepare a 1:1 demo.