Error editing multiple records when using grid.selectAll

Hi,

I’ve been using the data grid. I recently changed it to allow the user to select multiple records and edit them at the same time. Everything works perfectly if you select multiple rows on the grid using the shift key. I select multiple rows, click edit, enter the new value, and click save, and then click apply and all the records get sent to the servlet to save.

However, when I select multiple records using the grid.selectAll() method and click the apply button DHTMLX throws the following error:

TypeError: Unable to get property 'idd' of undefined or null reference
   at a._getRowData (http://localhost:8080/codebase/dhtmlx.js:9:848183)
   at dataProcessor.prototype._getAllData (http://localhost:8080/codebase/dhtmlx.js:9:1379468)
   at dataProcessor.prototype.sendAllData (http://localhost:8080/codebase/dhtmlx.js:9:1378971)
   at dataProcessor.prototype.sendData (http://localhost:8080/codebase/dhtmlx.js:9:1375924)
   at Anonymous function (http://localhost:8080/test/selectAllTest.html:121:21)
   at a.callEvent (http://localhost:8080/codebase/dhtmlx.js:9:19579)
   at _doOnMouseUp (http://localhost:8080/codebase/dhtmlx.js:9:438499)

On debugging, I found it looks like an extra entry with a null row id is added to the array of updated fields. This only happens in IE11, in Chrome it works fine. I was using DHTMLX 4.3, but upgraded to 5.1.0 hoping it would fix the problem.


Here’s my code:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
    <title>Test Grid</title>
    <script type="text/javascript" src="../codebase/dhtmlx.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
    <link rel="STYLESHEET" type="text/css" href="../codebase/dhtmlx.css">
    <link rel="STYLESHEET" type="text/css" href="../shared/dhxScreens.css">
    <script type="text/javascript">
        dhtmlx.image_path = "../codebase/imgs/";

        var test = {};

        function handleBodyLoad() {

            var data={
                rows:[
                    { id:1001, data:["valueA_1","valueB_1"] },
                    { id:1002, data:["valueA_2","valueB_2"] },
                    { id:1003, data:["valueA_3","valueB_3"] }
                ]
            };

            test.layout = new dhtmlXLayoutObject(document.body,"1C");
            test.layout.cells("a").setText("Test Grid");
            test.rfGrid = test.layout.cells("a").attachGrid();
            var labels  = ["ColumnA",      "ColumnB"];
            var filters = ["#text_filter", "#text_filter"];
            var ids     = ["columnA",      "columnB"];
            var widths  = ["100",          "150"];
            var aligns  = ["left",         "left"];
            var types   = ["ro",           "ed"];
            var sorting = ["str",          "str"];
            test.rfGrid.setHeader(labels.join(','));
            test.rfGrid.attachHeader(filters.join(','));
            test.rfGrid.setColumnIds(ids.join(','));
            test.rfGrid.setInitWidths(widths.join(','));
            test.rfGrid.setColAlign( aligns.join(','));
            test.rfGrid.setColTypes(types.join(','));
            test.rfGrid.setColSorting(sorting.join(','));

            test.rfGrid.setEditable(true);
            test.rfGrid.enableMultiselect(true);

            test.rfGrid.init();
            test.rfGrid.parse(data, "json");

            test.dp = new dataProcessor("servlet");
            test.dp.setTransactionMode("POST", true);
            test.dp.setUpdateMode("off", true); // auto update
            test.dp.defineAction("updated",function(response){ return dpRowSavedAction(response,8); });
            test.dp.defineAction("inserted",function(response){ return dpRowSavedAction(response,8); });
            test.dp.defineAction("deleted",function(response){ return dpRowSavedAction(response,8); });
            test.dp.defineAction("invalid",function(response){ return dpSaveFailedAction(response); });
            test.dp.defineAction("error",function(response){ return dpSaveFailedAction(response); });
            test.dp.init(test.rfGrid);
            var formData = [
                {type:"fieldset",  offsetTop:0, /*width:253,*/ list:[
                    {type:"input",  name: "columnB", label: "Column B", offsetTop:7,required:true,labelWidth:150, inputWidth: 650},
                    {type:"button", name:"save", value:"Submit", offsetTop:18}
                ]}
            ];
            buildControls(formData,875,310);
        }


        function buildControls(formData,dialogWidth,dialogHeight) {
            // Creates edit, history, deletion windows and toolbar
            var wins = new dhtmlXWindows();

            test.editWin = wins.createWindow("Edit", 20, 30, dialogWidth, dialogHeight);
            test.editForm = test.editWin.attachForm(formData);
            test.editWin.hide();
            test.editForm.bind(test.rfGrid);
            test.editForm.attachEvent("onButtonClick", function (id) {
                console.log("form id = " + id);
                // Form save (Add or Edit)
                if (test.editForm.validate()) {
                    var ids = test.rfGrid.getSelectedRowId();
                    var newVal = test.editForm.getItemValue("columnB");
                    console.log("setting field " + "columnB" + " to " + newVal);
                    if (ids){
                        ids = ids.split(",");
                        ids.forEach(function(rowId) {
                            test.rfGrid.cells(rowId, 1).setValue(newVal);
                            test.rfGrid.cells(rowId, 1).cell.wasChanged=true;
                            test.dp.setUpdated(rowId, true);
                        });
                    }
                    test.editForm.save();
                    test.editWin.hide();
                    test.editWin.setModal(false);
                    test.editWin.detachEvent(test.editWinCloseHandler);
                }
                return true;
            });

            var toolbar = test.layout.attachToolbar();
            toolbar.setIconsPath(dhtmlx.image_path);
            toolbar.loadStruct("testToolbar.xml");
            toolbar.attachEvent("onClick", function(id) {
            if(id === 'editRow') {
                    if(test.rfGrid.getSelectedRowId()) {
                        test.editWin.setText("Edit");
                        test.editWin.mode="edit";
                        test.editWin.setModal(true);
                        test.editWin.show();
                        test.editWinCloseHandler = test.editWin.attachEvent("onClose", function(id){
                            // This is a cancel close
                            test.editWin.hide();
                            test.editWin.setModal(false);
                            test.editWin.detachEvent(test.editWinCloseHandler);
                            return false;
                        });
                    } else {
                        alert('Please select a row to edit');
                    }
                } else if(id === 'applyChanges') {
                    test.dp.sendData();
                } else if (id === 'selectAll') {
                    test.rfGrid.selectAll();
                }
            });
        }
    </script>
</head>
<body onload="handleBodyLoad()">
</body>
</html>

testToobar.xml:

<?xml version="1.0"?>
<toolbar>
    <item id="editRow" type="button" text="Edit"/>
    <item id="applyChanges" type="button" text="Apply"/>
    <item id="sep1" type="separator"/>
    <item id="selectAll" type="button" text="Select All"/>
</toolbar>

For a little more information, I added a log statement after I have finished marking all the fields as updated and the extra row is not there at that point in time. So the error happens during the sendData() function, not during the test.rfGrid.selectAll() function or my code that sets the rows to updated.

                    if (ids){
                        ids = ids.split(",");
                        ids.forEach(function(rowId) {
                            test.rfGrid.cells(rowId, 1).setValue(newVal);
                            test.rfGrid.cells(rowId, 1).cell.wasChanged=true;
                            test.dp.setUpdated(rowId, true);
                        });
                    }
                    console.log(test.dp.updatedRows);

After clicking the select all button and saving the edit form, I see this message in the logs:
[object Array] [“1001”, “1002”, “1003”]

Unfortunately the problem cannot be reconstructed locally.
Please, make sure that you have no duplicating ids or the row with the id= “0”.
If the problem still occurs for you please, provide with a complete demo or share with a demo link, where it can be reconstructed.
Here you can find a tutorial:
docs.dhtmlx.com/tutorials__auxi … pport.html

I am attaching the demo as a zip. It looks like Chrome is also throwing the error too. I did find a work around though. If you uncomment the lines right before test.dp.sendData() it will get past this error and throw a 404 since I don’t have a servlet setup.

                    console.log(test.dp.updatedRows);
                    test.dp.updatedRows = test.dp.updatedRows.filter(function(r) {
                        return !!r;
                    });
                    console.log(test.dp.updatedRows);
                    test.dp.sendData();

The first log shows 4 rows (3 valid rows + 1 null row). The second log shows just the three valid rows.
test.zip (1.55 MB)

Please, try to remove the following lines:
test.editForm.bind(test.rfGrid);

test.editForm.save();
As you you are not perform binding and form editing. You change your grid directly through the API bypassing the form edit. But saving that form you are adding an additional item to the updateed items.

@sematik Thanks, that fixed it.