Updating a different column/cell's value while editing in Grid (Javascript es5)

Q.1) When I select Product, I want to update Rate and IsTaxable field on the same row for that product as well. How?
Q.2) If I update the Rate or Quantity which are just of editType default, I want to update Total Field based on those data. My Total Cell should not be editable manually though. How?
Q.3) When I select Product, I also want the ProductId to be set in DataRow object so that I can save ProductId in Transaction.


        var productElem;
        var productDDL;

        ej.grids.Grid.Inject(ej.grids.Edit, ej.grids.Toolbar); 
var grid = new ej.grids.Grid({
            dataSource: [],
            toolbar: ['Add', 'Cancel'],
            editSettings: { showConfirmDialog: true, showDeleteConfirmDialog: true, allowEditing: true, allowAdding: true, allowDeleting: true, mode: 'Batch' },
            columns: [
                {
                    field: 'Product', headerText: 'Product',
                    type: 'string',
                    foreignKeyField: "ProductId",
                    foreignKeyValue: "Product",
                    edit: {
                        create: function () {
                            productElem = document.createElement('input');
                            return productElem;
                        },
                        read: function () {
                            return productDDL.text;
                        },
                        destroy: function (e) {
                            productDDL.destroy();
                        },
                        write: function (args) {
                            productDDL = new ej.dropdowns.ComboBox({
                                fields: { text: 'product', value: 'product' },
                                placeholder: "Select a Product",
                                allowFiltering: true,
                                filtering: (e) => {
                                    if (!e.text || e.text.length < 3) { return; }
                                    else {
                                        var query = new ej.data.Query().addParams("searchText", e.text.trim());
                                        e.updateData(productDDLSource, query);
                                    }
                                },
                                change: (item) => {
// HERE I want to update value of Rate and IsTaxable based on Product selected
                                }
                            });

                            productDDL.appendTo(productElem);
                        },
                    }
                },
                { field: 'Rate', headerText: 'Rate', type: 'number' },
                { field: 'Quantity', headerText: 'Quantity', type: 'number' },
                { field: 'Total', headerText: 'Total', type: 'number' },
                { field: 'IsTaxable', headerText: 'Is Vatable', type: 'checkbox' }
            ],
            height: 315
        });
        grid.appendTo('#grid');

9 Replies 1 reply marked as answer

BS Balaji Sekar Syncfusion Team June 16, 2021 11:09 AM UTC

Hi Prabesh, 
  
Greetings from the Syncfusion support. 
  
We checked attached sample and we suspect that you have performed the Batch editing with ForeignKey column.  
 
In your code example we found that, you have not defined the column.isPrimaryKey property in the unique Grid column which is required to perform the CRUD action. 
  
Please refer the below documentation for more information 
  
  
Query: When I select Product, I want to update Rate and IsTaxable field on the same row for that product as well. How? 
  
Based on your query we can update Rate, IsTaxable column value when select Product using updateCell method in the change event dropdown editing. Please refer the below syntax and documentation for more information. 
  
Syntax:  
gridInstance.updateCell(rowIndex, field, value); 
  
  
From your code example, we need more details about your query to validate further so, please ensure the following details us. 
  
In your sample, we found that the Grid’s dataSource has been empty and you do not define the dataSource of foreignKeyColumn, dropdownlist editing which are required dataSource to perform the Grid’s CRUD action. 
  
In ForeignKeyColumn, you do not define the column.dataSource property in the foreignKeyColumn(Product) and you have tried to map the different columns value in field and foreignKeyField. By default, in ForeignKey column, bind the external table/JSON data to Grid column and it will display value from foreignKeyValue which is depending on unique values of column.field and column.foreignKeyField. 
  
We shared the Demo sample and documentation about the ForeignKeyColumn Feature. 
  
  
  
Note: By default, we are unable update the ForeignKeyField(ProductId) and we should define that foreignKeyColumn’s dataSource since we can map the ForeignKeyValue to Grid column using that columns dataSource. 
  
Also you have enabled the dropdown editing in Product column but dataSource is undefined. Since please ensure that you want to add the dataSource to dropdown editing while perform Grid’s Add action or we misunderstood please share exact requirement to us that will help to validate further. 
  
Regards, 
Balaji Sekar. 



PR Prabesh June 16, 2021 12:10 PM UTC

Hello Balaji,

Thanks for reply, 
gridInstance.updateCell(rowIndex, field, value); 

This seems to work for my first query. 

I am new to Syncfusion and I had no intention to use the primary or foreign keys. So, I have removed it from the code. For productId I have kept a hidden column now to update the productId value for rowObject.

But my second query still is unanswered
 Query: If I update the Rate or Quantity which are just of editType default, I want to update Total Field based on those data. My Total Cell should not be editable manually though. How?

I tried to achieve it using the cellSave event but turns out it does not have the current changes before that batch is saved. So, how do I catch the event when values of numericEdit or default edit are changed? My work requires the event to give me the real-time Row object when any edit field is updated.

I am open to using edit mode: "Normal" instead of mode: "Batch" if it provides a better way to do it.

My changes are as below:
      var productElem;
        var productDDL;

        ej.grids.Grid.Inject(ej.grids.Edit, ej.grids.Toolbar); 
var grid = new ej.grids.Grid({
            dataSource: [],
            toolbar: ['Add', 'Cancel'],
            editSettings: { showConfirmDialog: true, showDeleteConfirmDialog: true, allowEditing: true, allowAdding: true, allowDeleting: true, mode: 'Batch' },
            columns: [
                  { field: 'ProductId', headerText: 'ProductId', type: 'number', visible: false },
                {
                    field: 'Product', headerText: 'Product',
                    type: 'string',
                    edit: {
                        create: function () {
                            productElem = document.createElement('input');
                            return productElem;
                        },
                        read: function () {
                            return productDDL.text;
                        },
                        destroy: function (e) {
                            productDDL.destroy();
                        },
                        write: function (args) {
                            productDDL = new ej.dropdowns.ComboBox({
                                fields: { text: 'product', value: 'product' },
                                placeholder: "Select a Product",
                                allowFiltering: true,
                                filtering: (e) => {
                                    if (!e.text || e.text.length < 3) { return; }
                                    else {
                                        var query = new ej.data.Query().addParams("searchText", e.text.trim());
                                        e.updateData(productDDLSource, query);
                                    }
                                },
                                change: (item) => {
                                    grid.updateCell(currentRowIndex, "ProductId", item.itemData.productId);
                                    grid.updateCell(currentRowIndex, "Rate", item.itemData.rate);
                                    grid.updateCell(currentRowIndex, "IsVatable", item.itemData.isVatable);
                                }
                            });

                            productDDL.appendTo(productElem);
                        },
                    }
                },
                { field: 'Rate', headerText: 'Rate', type: 'number' },
                { field: 'Quantity', headerText: 'Quantity', type: 'number' },
                { field: 'Total', headerText: 'Total', type: 'number' },
                { field: 'IsTaxable', headerText: 'Is Vatable', type: 'checkbox' }
            ],
            height: 315
        });
        grid.appendTo('#grid');



BS Balaji Sekar Syncfusion Team June 17, 2021 02:35 PM UTC

Hi Prabesh, 
  
Thanks for your update. 
  
Query: If I update the Rate or Quantity which are just of editType default, I want to update Total Field based on those data. My Total Cell should not be editable manually though. How? 
  
We checked the attached sample code and you do not defined the primaryKey column in Grid as you provided sample code.  So, we suggest you to use the column.primaryKey property to perform the CRUD actions(add/edit/delete/update) which is default behaviour of Grid’s CRUD functionality. 
  
We can update the Total column value when change Rate and Quantity column value using input event of TextBox. In Grid default edittype as stringedit which is render the TextBox component in editmode and enable the input event using cellEditParams feature. 
  
We have prevented the Total column’s cell editing using cellEdit event. In this event we have set the cancel as true, if columnName is “Total” 
  
Please refer the below code example, sample and Help Documentation for more information. 
[index.js] 
function cellEdit(args) { 
  if (args.columnName == 'Total') { 
    args.cancel = true; 
  } 
} 
function totalChangeFn(e) { 
  var value = e.value == '' ? 1 : parseInt(e.value10); 
  var currentRow = grid.getRowInfo(e.container); 
  var rowIndex = currentRow.rowIndex; 
  var addedValue = grid.getBatchChanges().addedRecords; 
  var rate = addedValue[0]['Rate']; 
  grid.updateCell(rowIndex'Total'rate * value); 
} 
  
function rateChangeFn(e) { 
  var value = e.value == '' ? 1 : parseInt(e.value10); 
  var currentRow = grid.getRowInfo(e.container); 
  var rowIndex = currentRow.rowIndex; 
  var addedValue = grid.getBatchChanges().addedRecords; 
  var qty = addedValue[0]['Quantity']; 
  grid.updateCell(rowIndex'Total'qty * value); 
} 
  
  
                                                https://ej2.syncfusion.com/documentation/api/textbox/#input 
                                                https://ej2.syncfusion.com/documentation/grid/edit/#cell-edit-type-and-its-params   
  
Please get back to us, if you need further assistance. 
  
Regards, 
Balaji Sekar. 



PR Prabesh June 22, 2021 07:13 AM UTC

Hi Balaji,


Thanks for the reply. Your suggestion helped me a lot. I can now easily make updates as I want. I have also set the primary key as you have said. 

Going further into adding the next row, I came to the issue.


In both of the functions below, you are using index "0" for addedValue.  But, in real application, there can be rows that are added, updated or deleted and always keeping index "0" to get added or updated values cannot get us the correct object of added or updated Value. So, how can we identify correct addedValue or updatedValue in that case?

 var qty = addedValue[0]['Quantity'];

  var rate = addedValue[0]['Rate']; 





BS Balaji Sekar Syncfusion Team June 24, 2021 03:48 AM UTC

Hi Prabesh, 

We happy to hear that reported query has been achieved. 

Based on your query we can perform the Total column value updating based on Rate and Quantity values using Input events of TextBox editing and also it will help to perform the multiple rows while adding/ editing actions. 

Please refer the below code example and sample for more information. 

[index.js] 
 
function totalChangeFn(e) { 
  var value = e.value == '' ? 1 : parseInt(e.value10); 
  var currentRow = grid.getRowInfo(e.container); 
  var rowIndex = currentRow.rowIndex; 
  var addedValue = grid.getBatchChanges().addedRecords; 
  var row = null; 
  var cell = e.container.closest('.e-rowcell'); 
  var isAdd = cell.closest('tr').classList.contains('e-insertedrow'); 
 
  if (isAdd) { 
    row = addedValue.length == 1 ? addedValue[0] : addedValue[rowIndex]; 
  } 
 
  var rate = isAdd 
    ? row['Rate'] 
    : Number( 
        e.container.closest('tr').children[grid.getColumnByField('Rate').index] 
          .innerText 
      ); 
 
  grid.updateCell(rowIndex'Total'rate * value); 
} 
 
function rateChangeFn(e) { 
  var value = e.value == '' ? 1 : parseInt(e.value10); 
  var currentRow = grid.getRowInfo(e.container); 
  var rowIndex = currentRow.rowIndex; 
  var addedValue = grid.getBatchChanges().addedRecords; 
  var row = null; 
  var cell = e.container.closest('.e-rowcell'); 
  var isAdd = cell.closest('tr').classList.contains('e-insertedrow'); 
  if (isAdd) { 
    row = addedValue.length == 1 ? addedValue[0] : addedValue[rowIndex]; 
  } 
 
  var qty = isAdd 
    ? row['Quantity'] 
    : Number( 
        e.container.closest('tr').children[ 
          grid.getColumnByField('Quantity').index 
        ].innerText 
      ); 
 
  grid.updateCell(rowIndex'Total'qty * value); 
} 


Please get back to us, if you need further assistance. 

Regards, 
Balaji Sekar. 



PR Prabesh June 24, 2021 05:26 PM UTC

Hi Balaji,


Thank you for your assistance. This helped me achieve what I wanted to do. I'm really grateful.


The other thing is, I have another grid as well but in this new grid the Edit Mode needs to be "Normal".


Here, When I change the selection of Product combobox, I want to update the Values of Rate and Total (NumericEdit fields) and IsTaxable (boolean edit field) of the same row.

I found out that "grid.updateCell()" function does not work in Normal Mode.


Thanks for helping me out?


Regards,

Prabesh



BS Balaji Sekar Syncfusion Team June 29, 2021 12:24 PM UTC

Hi Prabesh, 

Thanks for your patience. 

Based on your query we can updating the Total column value based on Rate and Quantity values while enabled Normal editing using change event of NumericTextBox editing. In mentioned events, we have found the Rate and Quantity values and multiply those values then apply to Total column. 

Please refer the below code example and sample for more information. 

[index.js] 
var grid = new ej.grids.Grid({ 
  dataSource: [], 
  toolbar: ['Add''Cancel''Update'], 
  editSettings: { 
    showConfirmDialog: true, 
    showDeleteConfirmDialog: true, 
    allowEditing: true, 
    allowAdding: true, 
    allowDeleting: true, 
    mode: 'Normal' 
  }, 
  columns: [ 
    { 
      field: 'Id', 
      headerText: 'ID', 
      type: 'number', 
      isPrimaryKey: true, 
      width: 80 
    }, 
    { 
      field: 'ProductId', 
      headerText: 'ProductId', 
      type: 'number', 
      visible: false 
    }, 
    { 
      field: 'Product', 
      headerText: 'Product', 
      type: 'string', 
      edit: { 
        create: function() { 
          productElem = document.createElement('input'); 
          return productElem; 
        }, 
        read: function() { 
          return productDDL.text; 
        }, 
        destroy: function(e) { 
          productDDL.destroy(); 
        }, 
        write: function(args) { 
          productDDL = new ej.dropdowns.ComboBox({ 
            dataSource: dropdownData, 
            fields: { text: 'product'value: 'product' }, 
            placeholder: 'Select a Product', 
            allowFiltering: true, 
            filtering: e => { 
              if (!e.text || e.text.length < 3) { 
                return; 
              } else { 
                var query = new ej.data.Query().addParams( 
                  'searchText', 
                  e.text.trim() 
                ); 
                e.updateData(productDDLSourcequery); 
              } 
            }, 
            change: item => { 
              var tr = item.element.closest('tr'); 
              [].slice.call(tr.children).forEach(td => { 
                var comp = td.querySelector('.e-control'); 
                if (comp) { 
                  if (comp.id == grid.element.id + 'Rate') { 
                    comp.ej2_instances[0].value = item.itemData.rate; 
                  } 
                } 
              }); 
            } 
          }); 
 
          productDDL.appendTo(productElem); 
        } 
      } 
    }, 
    { 
      field: 'Rate', 
      headerText: 'Rate', 
      type: 'number', 
      editType: 'numericedit', 
      edit: { params: { change: rateChangeFn } } 
    }, 
    { 
      field: 'Quantity', 
      headerText: 'Quantity', 
      type: 'number', 
      editType: 'numericedit', 
      edit: { params: { change: totalChangeFn } } 
    }, 
    { field: 'Total'headerText: 'Total'type: 'number' } 
  ], 
  height: 315 
}); 
grid.appendTo('#Grid');  
 
function totalChangeFn(e) { 
  qty = e.value; 
  if (e.isInteracted) { 
    var tr = e.event.target.closest('tr'); 
    [].slice.call(tr.children).forEach(td => { 
      var comp = td.querySelector('.e-control'); 
      if (comp) { 
        if (comp.id == grid.element.id + 'Total') { 
          comp.ej2_instances[0].value = rate * e.value; 
        } 
      } 
    }); 
  } 
} 
 
function rateChangeFn(e) { 
  rate = e.value; 
  if (e.isInteracted) { 
    var tr = e.event.target.closest('tr'); 
    [].slice.call(tr.children).forEach(td => { 
      var comp = td.querySelector('.e-control'); 
      if (comp) { 
        if (comp.id == grid.element.id + 'Total') { 
          comp.ej2_instances[0].value = qty * e.value; 
        } 
      } 
    }); 
  } 
} 
 
   

Please get back to us, if you need further assistance. 

Regards, 
Balaji Sekar. 



PR Prabesh July 2, 2021 03:59 PM UTC

Dear Balaji,


I have achieved almost everything I wanted to so far with this grid. Thanks to you.

But I had to make a few changes. The rateChangeFn and totalChangeFn did not execute when rate/quantity fields were updated when editType was set to 'numerictext'. But when I removed editType entirely, the changeFn were executed as I wanted.


Also, js could not find the "e.isInteracted" property so I removed the if clause to check "e.isInteracted"  entirely. And I have achieved almost everything so far.

However, I also need the ProductId to be in the row object to save this all to the database. 

I use "grid.currentViewData" to get row objects but the ProductId is not set. I tried to udpate the productId the same way you updated Total Using td.querySelector('.e-control') But turns out it does not provide an input control if it's not visible. Is there a way to set ProductId property to set to the row so that whenever Product is changed, it sets a productId to row object.


I tried making it happen with Product Combobox by setting the Value portion of Product Combobox as ProductId. I did following to set value of Combobox as ProductId

           fields: { text: 'product'value: 'productId' }, 
           placeholder: 'Select a Product', 


and this to  read function of Combobox

        read: function() { 
          return productDDL.value; 
        }, 

 But turns out when the row is set back to view mode from edit mode, the ProductId is shown instead of Product in Grid view. 

I hope you get what I mean. Please let me know if you need any information from me.


Thanks and Regards,

Prabesh




BS Balaji Sekar Syncfusion Team July 6, 2021 10:34 AM UTC

Hi Prabesh, 

Query #1: The rateChangeFn and totalChangeFn did not execute when rate/quantity fields were updated when editType was set to 'numerictext' 

NumericTextbox editing, change events triggers when we focus out from the component or increment/decrement of value which is default behavior of NumericTextBox component. 

Query #2: Need the ProductId to be in the row object to save this . 

Based on your query,  we suspect that you need to update productid value based Product so, we suggest you to achieve this query using actionBegin event with save requestType while add action. If you edit the saved value we can update productId value using change event of combox component. 

Please refer the below code example and sample for more information. 

[index.js] 
    change: item => { 
              var tr = item.element.closest('tr'); 
              [].slice.call(tr.children).forEach(td => { 
                var comp = td.querySelector('.e-control'); 
                if (comp) { 
                  if (comp.id == grid.element.id + 'Rate') { 
                    comp.ej2_instances[0].value = item.itemData.rate; 
                  } 
                } 
              }); 
 
              if (grid.isEdit && grid.currentViewData.length > 0) { 
                var currentRow = grid.getRowInfo(item.element.closest('tr')); 
                var row = currentRow.rowData; 
                row['productId'] = item.value; 
                row['Product'] = item.itemData['product']; 
                grid.updateRow(currentRow.rowIndex, row); 
              } 
            } 
function actionBegin(args) { 
  if (args.requestType == 'save' && args.action == 'add') {     
    var row = dropdownData.filter(x => x.product == args.data['Product'])[0]; 
    args.data['productId'] = row['productId']; 
  } 
} 


Please get back to us, if you need further assistance. 

Regards, 
Balaji Sekar. 


Marked as answer
Loader.
Up arrow icon