We use cookies to give you the best experience on our website. If you continue to browse, then you agree to our privacy policy and cookie policy. Image for the cookie policy date

ejGrid: Cell Events (e.g. cellEdit) only fire in Batch Mode

See: http://jsplayground.syncfusion.com/nl0vyvcy

Scenario: I need to trigger workflow (populate default values based upon a selection within a cell) during entry of a new row. 

I'm using KnockoutJS and ideally the property value would be committed for the cell to the backing property on edit, however, the value is not updated until the row is committed. Therefore, I am seeking to intercept the CellEdit event and force the udpate to trigger my behavior, however, this only appears to be triggering when the Edit Mode is Batch.

Desired behavior: Trigger the cell edit events during Normal mode as well.

Any suggestions how to achieve this behavior?

Thank you.

Robert

9 Replies

PK Prasanna Kumar Viswanathan Syncfusion Team May 16, 2017 12:04 PM UTC

Hi Robert, 

Thanks for contacting Syncfusion support. 

Query : “Trigger the cell edit events during Normal mode as well” 

In Normal mode when we perform edit operation the edit form will be generated for the whole row. So, the value will updated for each cell when the whole row is submitted. If you need to update the cell value once you focus out, we suggest you to bind the focus out event for the cells.  

To bind the focus out event, use actionComplete event for ejGrid. In this event we check the requestType and bind the focus out event for each cell. 

Find the code example:  

 
$("#Grid").ejGrid({ 
            // the datasource "window.gridData" is referred from jsondata.min.js 
            dataSource: window.gridData, 
            allowPaging: true, 
            actionComplete: function (args) { 
                if (args.requestType == "beginedit") { 
                    this.element.find(".gridform").find("td").focusout(function () { 
                        debugger; 
                    }); 
                } 
            }, 


Refer to the Help document for the actionComplete event. 


Regards, 
Prasanna Kumar N.S.V 



RM Robert Mims May 16, 2017 12:15 PM UTC

Thank you, again, for your quick reply.

I'll give that a try.

Robert


RM Robert Mims May 17, 2017 12:31 PM UTC

I took your direction as inspiration and composed a custom KnockoutJS binding handler to allow for configuration of target properties and editors within a cell. Perhaps somebody else runs in to this need, so, sharing it here. To use it, just add a reference with your string property list after your ejGrid data binding instruction.

Example use:
ejUpdateCellOnLostFocus: [ 'productId', 'quantity' ]
The binding handler:
ko.bindingHandlers.ejUpdateCellOnLostFocus = {
    init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        /// <summary>Initializes the Syncfusion Cell Property Update binding handler</summary>
        /// <param name="element" type="Object">The target Syncfusion Grid</param>
        /// <param name="valueAccessor" type="Object">The binding configuration in the form of an array of property names.</param>
 
        var config = ko.utils.unwrapObservable(valueAccessor());
        if (config.constructor !== Array) {
            return;
        }
 
        // Safely store the configuration and grid identifier within this binding context so the extension can be reused
        bindingContext.$data.__ejUpdateCellOnLostFocus = config;
        bindingContext.$data.__ejUpdateCellOnLostFocus_gridId = element.id;
 
        $(element).ejGrid({
            actionComplete: function(args) {
                /// <summary>Grid Action Complete handler to adapt Syncfusion Grids to requirements, see: https://goo.gl/Bni3P8 </summary>
                /// <param name="args" type="Object">The grid event arguments</param>
                switch (args.requestType) {
                case ej.Grid.Actions.BeginEdit:
                    {
                        // By using array, you can trigger multiple properties for auto-update
                        $.each(bindingContext.$data.__ejUpdateCellOnLostFocus, function(i, v) {
                            // Attach a focus out handler to each target property wrapper, the DOM elements are removed on end edit, so, no clean-up
                            args.row.find("#" + bindingContext.$data.__ejUpdateCellOnLostFocus_gridId + v + "_wrapper").on("focusout", function () {
                                // Update the row data property with the value from the hidden input for the cell
                                args.rowData[v] = args.row.find("#" + bindingContext.$data.__ejUpdateCellOnLostFocus_gridId + v + "_input").val();
                            });
                        });
                        break;
                    }
                }
            }
        });
    }
};


PK Prasanna Kumar Viswanathan Syncfusion Team May 18, 2017 12:45 PM UTC

Hi Robert, 

Thanks for providing the information. 

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

Regards, 
Prasanna Kumar N.S.V 



RM Robert Mims May 18, 2017 05:56 PM UTC

One side-effect that I didn't notice when updating the row data value with focus out: it ends editing.

Is there some mutation observer or something that is causing an update to another property to end the edit operation?

Thank you.

Robert


RM Robert Mims May 18, 2017 09:00 PM UTC

To add a little more to the observed behavior. If I cancel the next grid event actionBegin -> refresh, the edit mode is retained and the underlying value updated - but not reflected within the grid.My multiple-revision question, then, is:I want to update the value without ending the continuous edit operations (tab from cell that just changed, whose value updated another) and have it reflected within the grid (given that I am using KnockoutJS.) In examining the KO Widget source, I believe the call to refreshTemplate is where I lose my edit state. 


RM Robert Mims May 18, 2017 11:21 PM UTC

Current state:

I've added a case to the actionComplete event that takes data from the BeginEdit and on Refresh instead of cancelling, it waits for 25ms and begins the edit again.

What I'd like to do is, using normal edit mode, select and edit the next cell within the grid.

I've tried (perhaps incorrectly) selectCells (e.g. [[ current row index, [ next column index]]] as the argument) to no avail. 

Given I am not in batch edit mode, is there a way to activate edit of a row and then a specific cell (column) within that row?

I've tried jQuery selectors, however, the internal state of the diagram changes based on invocations of methods/state management and the classes need to be changed too - so, it seems this is something that I need to accomplish with existing methods within the grid.

Thank you.

Robert


PK Prasanna Kumar Viswanathan Syncfusion Team May 19, 2017 01:10 PM UTC

Hi Robert, 

Before we proceed with your query, we need some clarifications.  

1. In focus out event do you need to update only the current cell value?  

2. “To add a little more to the observed behavior. If I cancel the next grid event actionBegin -> refresh, the edit mode is retained and the underlying value updated - but not reflected within the grid” 

Please provide more information for the above query.  

Regards, 
Prasanna Kumar N.S.V 



RM Robert Mims May 19, 2017 01:21 PM UTC

Answers:

1. Yes, and the underlying property change (Knockout Observable) has a subscription that changes the value of another bound column within the grid which should be reflected.

2. What I was describing here is that cancelling the next actionComplete event where the requestType is Refresh retained the edit mode state, however, that workflow was necessary in order to update the dependent cell value.

Ideally, we could decorate a column bound to a Knockout observable as updating immediately. The subscription on the observable in the dependent column would then update on change notification and the edit mode retained. 

My current binding handler workaround (though it doesn't retain the current edit column) looks like this where the grid row selection and start edit attempt to remedy that the refresh request updated the row template but ended the edit request and focus on the next cell after the BeginEdit -> FocusOut value assignment to the underlying view model observable:

ko.bindingHandlers.ejUpdateCellOnLostFocus = {
       init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
           /// <summary>Initializes the Syncfusion Cell Property Update binding handler</summary>
           /// <param name="element" type="Object">The target Syncfusion Grid</param>
           /// <param name="valueAccessor" type="Object">The binding configuration in the form of an array of property names.</param>
 
           var config = ko.utils.unwrapObservable(valueAccessor());
           if (config.constructor !== Array) {
               return;
           }
 
          $(element).data("__ejUpdateCellOnLostFocus", config);
 
           $(element).ejGrid({
               actionComplete: function(args) {
                   /// <summary>Grid Action Complete handler to adapt Syncfusion Grids to requirements, see: https://goo.gl/Bni3P8 </summary>
                   /// <param name="args" type="Object">The grid event arguments</param>
                   switch (args.requestType) {
                   case ej.Grid.Actions.BeginEdit:
                       {
                           var gridId = args.target.id, properties = $(args.target).data("__ejUpdateCellOnLostFocus");
                           $.each(properties, function (i, v) {
                               args.row.find("#" + gridId + v + "_wrapper").on("focusout", function () {
                                   var val = args.row.find("#" + gridId + v + "_input").val();
                                   if (args.rowData[v] !== val) {
                                       $(args.target).data("__actionCompletedFor", { rowIndex: args.rowIndex, property: v });
                                       args.rowData[v] = val;
                                   }
                               });
                           });
                           break;
                       }
                   case ej.Grid.Actions.Refresh:
                       {
                           setTimeout(function() {
                                   var workaround = $(args.target).data("__actionCompletedFor");
                                   if (workaround) {
                                       var grid = $(args.target).data("ejGrid"),
                                           columnIndex = grid.getColumnIndexByField(workaround.property) + 1;
 
                                       grid.selectRows(workaround.rowIndex);
                                       grid.startEdit(grid.getRowByIndex(workaround.rowIndex));
                                       
                                       // TODO: Select the next cell and focus
 
                                       $(args.target).data("__actionCompletedFor", null);
                                   }
                               },
                               25);
                           break;
                       }
                   }
               }
           });
       }
   };

Loader.
Up arrow icon