Skip to content

DataGrid and TreeList: Editing API Enhancements #13636

Description

@jtoming830

The Problem

The DataGrid and TreeList components do not provide an API to perform the following tasks:

  • Get or set updated/inserted/deleted rows
  • Save all rows in one request in batch edit mode
  • Cancel changes made to an individual row in batch edit mode
  • Be notified when editing is finished

The Proposed Solution

We plan to introduce the following API:

Options

editing.editRowKey: any // key for the edited row

editing.editColumnName: string // name of the edited column

editing.changes: object[] // pending row changes 

changes is an array of objects with the following fields:

  • type - "insert", "update", or "remove"
  • data - the row's updated data fields
  • key - the row's key

Events

onSaving: function // A callback function that is executed before edited data is saved

onSaved: function // A callback function that is executed after edited data is saved

onEditCanceling: function // A callback function that is called before editing is canceled

onEditCanceled: function // A callback function that is called after editing is canceled

Utils

DevExpress.data.applyChanges(data, changes, { keyExpr, immutable }) // A method that applies changes to data
  • data - the current dataset
  • changes - changes to be applied to the dataset
  • keyExpr - specifies the key property
  • immutable - if true, applyChanges returns a new array instead of modifying data

The applyChanges method makes it easier to update the grid's data source. If this method does not meet your requirements, you can use your own update implementation instead.

Controlled Mode

You can use the newly introduced API to implement your own data-saving logic in the onSaving handler. To handle data modification manually, set the cancel parameter to true to disable the default saving implementation as follows:

Angular
// app.component.html

<dx-data-grid
  keyExpr="ID"
  [dataSource]="data"
  (onSaving)="onSaving($event)" 
>
  <dxo-editing 
    mode="batch"

    [allowUpdating]="true"

    [(changes)]="changes"
    [(editRowKey)]="editRowKey"
    [(editColumnName)]="editColumnName"
  ></dxo-editing>
</dx-data-grid>

. . .

// app.component.ts
export class AppComponent {
    data: any[];
    editRowKey: any;
    editColumnName: string;
    changes: Array<any>;

    constructor(service: Service) {
        this.data = service.getData();
        this.editRowKey = null;
        this.editColumnName = null;
        this.changes = [];
    }

    onSaving(e) { 
        e.cancel = true;  // cancel automatic update of the data array

        // await fetch(. . .);  // save data to your remote server if needed

        // apply changes to your local data
        // you can use our applyChanges method or implement your own data modification logic
        applyChanges(this.data, this.changes, {
          keyExpr: 'ID',
          immutable: false
        });

        this.editRowKey = null;
        this.editColumnName = null;
        this.changes = [];
    }
}
React
const [editColumnName, setEditColumnName] = useState(null); 
const [editRowKey, setEditRowKey] = useState(null); 
const [changes, setChanges] = useState(null); 
const [data, setData] = useState([]); 

. . . 

<DataGrid
  keyExpr="ID"
  dataSource={data} 
  onSaving={onSaving} 
> 

  <Editing 
    mode="batch"

    allowUpdating={true}

    changes={changes} 
    onChangesChange={setChanges}

    editRowKey={editRowKey} 
    onEditRowKeyChange={setEditRowKey} 

    editColumnName={editColumnName} 
    onEditColumnNameChange={setEditColumnName} 
  /> 
</DataGrid>

. . . 

onSaving(e) { 
    e.cancel = true;  // cancel automatic update of the data array

    // await fetch(. . .);  // save data to your remote server if needed

    // apply changes to your local data
    // you can use our applyChanges method or implement your own data modification logic
    const newData = applyChanges(data, changes, {
      keyExpr: 'ID',
      immutable: true
    });

    setData(newData); 
    setChanges([]); 
    setEditColumnName(null); 
    setEditRowKey(null);
  });
} 
Vue
<template>
  <div>
    <DxDataGrid
      key-expr="ID"
      :data-source="data"
      @saving="onSaving"
    > 
      <DxEditing 
        mode="batch"

        :allow-updating="true"

        :changes.sync="changes"
        :edit-row-key.sync="editRowKey"
        :edit-column-name.sync="editColumnName"
      />
    </DxDataGrid>
  </div>
</template>

. . . 

export default {
  data() {
    return {
      data: [. . .],
      editRowKey: null,
      editColumnName: null,
      changes: []
    };
  },
  methods: {
    onSaving(e) { 
      e.cancel = true;  // cancel automatic update of the data array

      // await fetch(. . .);  // save data to your remote server if needed

      // apply changes to your local data
      // you can use our applyChanges method or implement your own data modification logic
      applyChanges(this.data, this.changes, {
        keyExpr: 'ID', 
        immutable: false
      });

      this.editRowKey = null;
      this.editColumnName = null;
      this.changes = [];
    }
  },
};
jQuery
$('#gridContainer').dxDataGrid({
    dataSource: data,
    editing: {
        mode: 'batch',
        allowUpdating: true,
    },
    onSaving: function(e) { 
        e.cancel = true;  // cancel automatic update of the data array

        // await fetch(. . .);  // save data to your remote server if needed

        // apply changes to your local data
        // you can use our applyChanges method or implement your own data modification logic
        DevExpress.data.applyChanges(data, e.changes, {
          keyExpr: 'ID', 
          immutable: false
        });
        e.component.option({
            dataSource: data,
            editing: {
                editRowKey: null,
                editColumnName: null,
                changes: []
            }
        });
    }
});

Send All Changes in a Single Request

In batch edit mode, the DataGrid sends a separate request for each object in the changes array. To optimize this operation and send all changes in one request, implement the onSaving event handler with the cancel parameter set to true. This cancels the DataGrid's default saving behavior and allows you to use your own implementation.

Angular
// app.component.html
<dx-data-grid 
  [dataSource]="store"
  (onSaving)="onSaving($event)" 
>
  <dxo-editing 
    mode="batch"
    [allowUpdating]="true"

    [changes]="changes"
    [editRowKey]="editRowKey"
  ></dxo-editing>
</dx-data-grid>

. . .

// app.component.ts
import * as AspNetData from "devextreme-aspnet-data-nojquery";

. . .

export class AppComponent {
    store: any;
    changes: any[];
    editRowKey: any;

    constructor(service: Service) {
        this.store = AspNetData.createStore( . . . );
        this.changes = [];
        this.editRowKey = null;
    }

    onSaving(e) {
        e.cancel = true;  // prevent DataGrid from sending a separate request for each element in the changes array
        const changes = e.changes;

        // assign the promise returned from fetch to the promise field to display the load panel during remote saving
        // if this promise is rejected, the DataGrid displays the error row 
        e.promise = fetch(. . .).then(() => {
            this.editRowKey = null;
            this.changes = [];
            this.store.push(changes);  // use store's Push API to apply changes locally
        }); 
    }
}

Refer to the first example to convert this code to React, Vue, or jQuery.

Handle Events Raised When Editing is Finished

Angular
// app.component.html
<dx-data-grid 
  [dataSource]="data"
  (onSaved)="onSaved($event)"
  (onEditCanceled)="onEditCanceled($event)"
>
  <dxo-editing 
    mode="batch"
    [allowUpdating]="true"
  ></dxo-editing>
</dx-data-grid>

. . .

// app.component.ts
export class AppComponent {
    data: any[];

    constructor(service: Service) {
        this.data = service.getData();
    }

    onSaved(e) {
        alert('data was saved');
    }
    
    onEditCanceled(e) {
        alert('editing was canceled');
    }
}

Refer to the first example to convert this code to React, Vue, or jQuery.

Try It

Live Sandboxes

We Need Your Feedback

Take a Quick Poll

Do you find DataGrid and TreeList editing API enhancements useful?

Get Notified of Updates

Subscribe to this thread - or to our Facebook and Twitter accounts - for updates on this topic.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions