How to reorder rows using drag and drop inside same grid and change value in row in batchedit grid

Hi.
I have a child grid in BatchEdit mode where i have a list of operations. I have a column named 'Ordem' which i use to sort the records.
Heres an image:
The values of the order are editable but i want it to be automatic. When i add a new row i allready set the value +1 to the bigger value in the rows.
But what i want is to drag and drop and "reorder" the rows by changing the value in the 'Ordem' column.
I used the code in this https://www.syncfusion.com/forums/149580/how-to-reorder-rows-using-drag-and-drop-inside-same-grid example, and have made some improvements where i can set the values, but they are not in green like when if i edited them manually.
The code:
function RowDrop(args) {
var dropSelectedRowIndex = [];
let gObj = this; //document.getElementById('Grid').ej2_instances[0];
let seletedRowIndexes = gObj.getSelectedRowIndexes();
if (gObj.sortSettings.columns.length > 0) {
let startedRow = args.rows[0];
let startRowIndex = parseInt(startedRow.getAttribute("aria-rowindex"), 10); //get the index of selected row
//if (!args.target) return
let targetRow = args.target.closest('tr');
if (targetRow == null) return;
let targetRowIndex = targetRow.rowIndex; //get the target row index where the row should place
gObj.getContentTable().querySelector('tbody').insertBefore(startedRow, targetRow);

if (!ej.base.isNullOrUndefined(targetRow.nextElementSibling)) {
let currentIndex = targetRow.rowIndex;
if (currentIndex <= startedRow.rowIndex) { // check with selected index and target index
gObj.getContentTable().querySelector('tbody').insertBefore(startedRow, targetRow);
} else {
gObj.getContentTable().querySelector('tbody').insertBefore(startedRow, targetRow.nextElementSibling);
}
} else {
gObj.getContentTable().querySelector('tbody').insertBefore(targetRow, startedRow);
}

let startRowObj = gObj.getRowObjectFromUID(startedRow.getAttribute('data-uid'));
let targetRowObj = gObj.getRowObjectFromUID(targetRow.getAttribute('data-uid'))
for (let i = 0, len = gObj.currentViewData.length; i < len; i++) {
let getDataByField = gObj.currentViewData[i]; //fetch the selected row using index in grid current view datas
if (gObj.sortSettings.columns.length > 0) {
sortedCurrentViewData = gObj.currentViewData;
sortedCurrentViewData.splice(targetRowIndex, 0, sortedCurrentViewData.splice(startRowIndex, 1)[0]); // take the target row using splice gObj.rowDragAndDropModule.removeBorder(targetRow);

//Corrects the order of the row.
let start = Math.min(startRowIndex, targetRowIndex);
let end = Math.max(startRowIndex, targetRowIndex);
let grid = this.element.ej2_instances[0];
for (let i = start; i <= end; i++) {
//grid.updateCell(i, 'Ordem', i + 1);
gObj.currentViewData[i].Ordem = i + 1;
}

gObj.contentModule.refreshContentRows();
dropSelectedRowIndex.push(targetRowIndex);
if (gObj.sortSettings.columns.length > 0) {
args.cancel = true;
}
if (dropSelectedRowIndex.length > 0) {
gObj.clearSelection();
gObj.selectRows(dropSelectedRowIndex);
}
}
}
}
}
If i replace the line "gObj.currentViewData[i].Ordem = i + 1;" with "grid.updateCell(i, 'Ordem', i + 1);" i can see the cells changing the values, but then they dont get saved. Like in this video:

Is there any way in the end of correcting the 'Ordem' values of the rows, to mark them as edited and to signal the grid that had changes maded?
Thanks

6 Replies

PG Praveenkumar Gajendiran Syncfusion Team April 20, 2021 10:22 AM UTC

Hi Emiliano,

Greetings from Syncfusion support.

Based on your query, we would like to inform you that by default in EJ2 Grid, while Drag and Drop the rows in the Grid, the changes are made only in the Grid UI and it will not affect the database. If you have to preform the Sorting after the row reordering, It will change the row order because the sorting actions need to be performed based on the Grid database, in this case we cannot maintain that row reorder. This is our default behavior.
  
In your provided information, we could see that you have used a UpdateCell method, By default in EJ2 Grid editing feature requires a primary key column(unique column) for CRUD operations. Because all the CRUD actions in the grid component are done based on the primaryKey. So please ensure this in your sample and use a unique column in your dataSource as primaryKey column to perform the CRUD operations. Refer the below document for more information.

Documentation: https://ej2.syncfusion.com/aspnetmvc/documentation/grid/edit/ 
As a Database constrain, we cannot able to change the primaryKey column(unique column) value dynamically. The same behavior in Grid also. By default, all the CRUD actions in the grid component are done based on the primaryKey value. So, we are unable to change the primaryKey value.  

Regards,
Praveenkumar G  



EM Emiliano April 20, 2021 02:09 PM UTC

Based on your query, we would like to inform you that by default in EJ2 Grid, while Drag and Drop the rows in the Grid, the changes are made only in the Grid UI and it will not affect the database.

I know. I want to reorder visually the rows, and ONLY THEN, mark some cells of eordered rows as edited by user (if it was him as edited some values), so the user can submit the changes to server.


If you have to preform the Sorting after the row reordering, It will change the row order because the sorting actions need to be performed based on the Grid database, in this case we cannot maintain that row reorder. This is our default behavior.

I though i should had a sorted column to have the rows ordered. if i have to give up the sorted column to achieve my intentions, it's ok.

In your provided information, we could see that you have used a UpdateCell method, By default in EJ2 Grid editing feature requires a primary key column(unique column) for CRUD operations. Because all the CRUD actions in the grid component are done based on the primaryKey. So please ensure this in your sample and use a unique column in your dataSource as primaryKey column to perform the CRUD operations. Refer the below document for more information.

Documentation: https://ej2.syncfusion.com/aspnetmvc/documentation/grid/edit/ 



I have a primary key column in my code:

    function DetailDataBoundAmostrasOperacoes(e) {
        var gridAmostrasOperacoes = new ej.grids.Grid({
            dataSource: new ej.data.DataManager({
                url: '@Url.Action("DataSource", "AmostrasOperacoes")',
                @*insertUrl: '@Url.Action("Insert", "AmostrasOperacoes")',
                updateUrl: '@Url.Action("Update", "AmostrasOperacoes")',
                removeUrl: '@Url.Action("Remove", "AmostrasOperacoes")',
                adaptor: new ej.data.UrlAdaptor,*@
                batchUrl: '@Url.Action("BatchUrl", "AmostrasOperacoes")',
                adaptor: new ej.data.RemoteSaveAdaptor,
                crossDomain: true
            }),
            showColumnChooser: true,
            width: '1400px',
            allowResizing: true,
            allowTextWrap: true,
            //allowSorting: true,
            allowRowDragAndDrop: true,
            sortSettings: {
                columns: [{ field: 'Ordem', direction: 'Ascending' }]
            },
            toolbar: ['Add', 'Edit', 'Delete', 'Update', 'Cancel', 'ColumnChooser'],
            editSettings: {
                allowAdding: true, allowEditing: true, allowDeleting: true,
                allowEditOnDblClick: true, //showDeleteConfirmDialog: false,
                mode: 'Batch',
                newRowPosition: 'Bottom'
            },
            selectionSettings: { cellSelectionMode: 'Box', type: 'Multiple', mode: 'Cell' },
            columns: [
                { field: 'Id', isPrimaryKey: true, visible: false, showInColumnChooser: false },
                { field: 'IdAmostras', defaultValue: e.data.Id, type: "number" , visible: false, showInColumnChooser: false },
                {
                    field: 'Ordem', textAlign: 'Center', visible: false, showInColumnChooser: false, defaultValue: 1,
                    type: 'numeric', format: 'N0', edit: { params: { decimals: 0, format: 'N', ShowSpinButton: false } },
                    editType: 'numericedit', width: 70, allowSorting: false
                },
                { field: 'Operacao', allowSorting: false, width: 100, defaultValue: '' },
                {
                    field: 'DataPrevista', headerText: 'Data Prevista', type: 'date',
                    format: { type: 'date', format: 'yyyy-MM-dd' },
                    editType: 'datepickeredit', allowSorting: false, width: 70
                },
                {
                    field: 'DataEfetuada', headerText: 'Data Efetiva', type: 'date',
                    format: { type: 'date', format: 'yyyy-MM-dd' },
                    editType: 'datepickeredit', allowSorting: false, width: 70
                },
                {
                    field: 'Obs', allowSorting: false,
                    //edit: {
                    //    create: "createTextArea", read: "readTextArea", destroy: "destroyTextArea", write: "writeTextArea"
                    //},
                    defaultValue: ''
                }
            ],
            load: function (args) {
                this.query = new ej.data.Query().where('IdAmostras', 'equal', e.data.Id);
                Load.call(this, args);
            },
            beforeBatchAdd: BeforeBatchAddAmostrasOperacoes,
            rowDrop: RowDropAmostrasOperacoes
        });
        gridAmostrasOperacoes.appendTo(e.detailElement.querySelector('.gridAmostrasOperacoes'));
    }



As a Database constrain, we cannot able to change the primaryKey column(unique column) value dynamically. The same behavior in Grid also. By default, all the CRUD actions in the grid component are done based on the primaryKey value. So, we are unable to change the primaryKey value. 

I dont want to change primaryKey. I only want a way to the user reorder some rows, by using Drag and Drop and ONLY THEN change some values in those rows, so i can mark them as edit by user, so the user can submit them to server as if was him who made the changes.

Like this, but automatically:



EM Emiliano April 20, 2021 02:14 PM UTC

Can you imagine if the user have 20 rows or more and want to make the last row, the first one? It will have to change all rows values manually!!!
Isn't any way to change the order of the rows after a Drag and Drop just to send the new order to server? I think this is a valid problem with a valid use case.
Change rows order with drag and drop and save the changes to the server. But use BatchEdit to only send the changes... not all the rows.


EM Emiliano April 20, 2021 06:05 PM UTC

It's close!!!

With the example in this topic, which is the same question i have, i made this:

var grid = new ej.grids.Grid({
        editSettings: { allowEditing: true, allowAdding: true, allowDeleting: true, mode: 'Batch', newRowPosition: 'Bottom' },
        //allowPaging: true,
        allowSorting: true,
        //pageSettings: { pageCount: 5 },
        allowRowDragAndDrop: true,
        allowSorting: true,
        sortSettings: {
            columns: [{ field: 'Ordem', direction: 'Ascending' }] //For drag and drop to work correctly, only one column should be used
        },
        beforeBatchAdd: function (args) {
            if (this.currentViewData.length > 0 && args.defaultData.Ordem == 1)
                args.defaultData.Ordem = Math.max(...this.currentViewData.map(x => x.Ordem)) + args.defaultData.Ordem;
        },
        rowDrop: function (args) {
            let minIndex = Math.min(args.fromIndex, args.dropIndex);
            let maxIndex = Math.max(args.fromIndex, args.dropIndex);
            //Get the index list between the moved rows.
            let list = this.currentViewData.slice(minIndex, maxIndex + 1).map(x => x.Ordem);

            //Because the moved row does not change position until the end of this event, we have to know if we are moving up or down.
            //Because if the row is going up, the row its still in last position, but will receive the smallest or first index cause it will go to the top.
            //If the row is going down, the moved row it's in the first position but should receive the last or biggest index in the list.
            if (args.dropIndex == args.fromIndex) //If the row didn't change index, do nothing.
                return;
            else if (args.fromIndex > args.dropIndex)
                list.push(list.shift()); //Shift removes the first index and push puts it at end (moved row is at the top and is going to the last)
            else
                list.unshift(list.pop()); //Pop removes the last index and unshift puts it at start (moved row is in the bottom and is going to be at the top)

            for (var i = minIndex; i <= maxIndex; i++)
                this.updateCell(i, "Ordem", list.shift()); //Just set the index rows as we are eliminating the indexs elements.
        },
        batchCancel: function (args) {
            //Makes the order of the rows back to original. Because normal 'batchCancel' only reset the row values leaving the rows in wrong order.
            this.refresh();
        },
        toolbar: ['Add', 'Edit', 'Delete', 'Update', 'Cancel'],
        load: function () {
            let data = new ej.data.DataManager({ url: "/Home/UrlDatasource", batchUrl: "/Home/BatchUpdate", adaptor: new ej.data.UrlAdaptor });
            grid.dataSource = data;
        },
        columns: [
            { field: 'Ordem', width: 140, headerText: 'Ordem', allowSorting: false, defaultValue: 1 },
            { field: 'OrderID', headerText: 'Order ID', textAlign: 'Right', width: 120, isPrimaryKey: true, allowSorting: false },
            { field: 'ShipCity', headerText: 'Ship Country', width: 140, allowSorting: false }
        ]
    });
        grid.appendTo('#Grid');
    });

I can move the rows, and the 'Ordem' column is changed to the correct values and the changes are marked as edited by user to be submitted. It's almost perfect.

I only have one problem, that if i try to make a second drag and drop the grid shows the message "Unsaved changes will be lost. Are you sure you want to continue?" and i dont want that. Is it possible to avoid this?



EM Emiliano April 21, 2021 08:37 AM UTC

A sample demo to demonstrate this code working.

Attachment: UrlAdaptorCRUDBatchMode_with_Drag_and_Drop_sending_to_server_1fb2aaf.zip


PG Praveenkumar Gajendiran Syncfusion Team April 21, 2021 12:15 PM UTC

Hi Emiliano,

Thanks for your update.

We have created a new incident under your Direct trac account to follow up with this query. We suggest you to follow up with the incident for further updates. Please log in using the below link.     

Regards,
Praveenkumar G 


Loader.
Up arrow icon