How do I detect success or failure of crud operation when using ej.data.UrlAdaptor() with Grid ?

I am using ej.data.DataManager to populate the grid from a local php file and using 


"crudUrl : 'crud.php'," to carry out update / delete operations.

The database is updated correctly and the grid reflects the changes when editing the data
(using the edit dialog).


I would like to give feedback to the user (a toast message) if the data fails to save (eg
record updated).

With a XMLHttpRequest() i would use something like this :-
-------------------------------------------
success: function (response) {
console.log('response' + response);
}

How do I do a similar thing using Datamanger / Grid ?, is it possible ?




10 Replies

MR Mohanraj Rengasamy Syncfusion Team May 2, 2025 11:43 AM UTC

  

Hi P Collishaw,


Thank you for reaching out.


When using the ej.data.UrlAdaptor() with Syncfusion's JavaScript Grid, you can detect the success or failure of CRUD operations by handling the actionComplete and actionFailure events in the Grid component.
 

 

const dataManager = new ej.data.DataManager({

  url: 'https://services.syncfusion.com/js/production/api/UrlDataSource',

  adaptor: new ej.data.UrlAdaptor(),

});

var grid = new ej.grids.Grid({

  dataSource: dataManager,
 

    .     .    .
 

  actionComplete: actionComplete,

  actionFailure: actionFailure,

});

grid.appendTo('#Grid');

 

function actionComplete(args) {

  // This event triggers when CRUD action is completed successfully

  if (args.requestType === 'save') {

      console.log('Record saved successfully');

      // You can access the saved data via args.data

  } else if (args.requestType === 'delete') {

      console.log('Record deleted successfully');

  }


 

function actionFailure(args) {

  // This event triggers when CRUD operation fails

  console.log('Operation failed with error: ', args.error);

}

 


Sample: https://stackblitz.com/edit/pb5sx2a4-oym9musz?file=index.js,index.html
 

For additional reference, please check the following documentation:

https://ej2.syncfusion.com/javascript/documentation/api/grid/#actionfailure

https://ej2.syncfusion.com/javascript/documentation/api/grid/#actioncomplete
https://ej2.syncfusion.com/javascript/documentation/grid/connecting-to-adaptors/url-adaptor#handling-crud-operations

Note: Ensure your crud.php returns a valid JSON response. Invalid JSON (e.g. empty string) will trigger actionFailure.


If you need any further clarification or assistance, feel free to reach out.


Regards,

Mohanraj Rengasamy



PC P Collishaw replied to Mohanraj Rengasamy May 3, 2025 04:39 AM UTC

Thank you Moharaj, much appreciated.


I'm on holiday for a week and dont have access to my code but will check as soon as I'm home and will reply with a code snippet if it works (the php side to help other users).


Thanks again.



RR Rajapandi Ravi Syncfusion Team May 5, 2025 04:46 AM UTC

P Collishaw,


Thanks for the update. We will wait to hear from you.



PC P Collishaw replied to Rajapandi Ravi May 11, 2025 11:05 AM UTC

Hello,


I am unable to return a valid JSON response, when I attempt to do so the dialog box doesn't close and in the console i get a "[EJ2Grid.Warning]: [object Object]" , the array has "YY.editFailure" for example.


From php I returned the array like this 

$response['connection_error'] = 0;
$response['error'] = 0;
$response['numrows'] = mysqli_affected_rows($conn);
echo json_encode($response);
---------------------------------------------------------------------------
This gives the error above (i want to be able to display a toast message that states "1 record updated "
(or if the update did not work, display a "no record updated" message))

If I do not echo the response (or echo an empty response), the the dialog closes and i do not get an error and the actionComplete function is triggerred.


I must be doing something wrong, can you advise ?


Thanks

Paul



KM Kishore Muthukrishnan Syncfusion Team May 12, 2025 11:13 AM UTC

Hi P Collishaw,


This issue typically occurs when the response data isn't returned in valid JSON format. Please ensure the server is returning the updated data in properly structured JSON format. Additionally, to show toast message when the data is updated or when update did not work, you can use syncfusion's toast control in actionComplete and actionFailure event. Please refer to the below code snippet and sample for more information.


function actionComplete(args) {

    if (args.requestType === 'save') {

        if (args.data) {

            showToast('Record updated successfully');

        }

    }

}

 

function actionFailure(args) {

    // This event triggers when CRUD operation fails

    showToast('Operation failed with error: ' , args.error);

}

 

function showToast(message) {

    var toast = new ej.notifications.Toast({

        content: message,

        position: { X: 'Right', Y: 'Top' },

        timeOut: 3000,

        target: document.body,

    });

    toast.appendTo('#element');

    toast.show();

}


Sample : https://stackblitz.com/edit/wz9tmovh?file=index.js,index.html

Documentation : https://helpej2.syncfusion.com/javascript/documentation/grid/connecting-to-adaptors/url-adaptor#handling-crud-operations ,
https://helpej2.syncfusion.com/javascript/documentation/toast/es5-getting-started
 

Regards,

Kishore Muthukrishnan



PC P Collishaw May 13, 2025 05:39 AM UTC

Thank you Kishore ,


I dont think I've explained my situation clearly, I want to return specific values (eg the number of records updated ).


If i return no  json, then your code (actionComplete) above works, but if i try and return my own data then actionFailure is triggerred.


In my php file that i pull the grids data from ("url: 'grid_pdo_data.php',) i return the data successfully like this 

----------

while($row = $stmt->fetch(PDO::FETCH_ASSOC)){

$data[] = array(

'id' => $row['id'],

'model' => $row['model'],

 'serial' => $row['serial'],

'comments' => $row['comments'],

'cimage' => base64_encode($row['cimage']),

);

}

$response=array("result"=>$data,"count"=>(int)$count);
echo json_encode($response);
--------------------------------

This works perfectly fine, do you have an example of how I can do a similar thing with a mysql update / delete or insert





RR Rajapandi Ravi Syncfusion Team May 14, 2025 11:13 AM UTC

P Collishaw,


You can customize your server response and inform the Grid that the operation succeeded by overriding the processResponse method using a custom adaptor that extends UrlAdaptor. This allows you to return custom data like affected row count, while keeping the Grid behavior consistent. Please refer the below code example and sample for more information.


HomeController.cs

 

//in the update method, we have returned the affected rows count

 

public IActionResult Update([FromBody]CRUDModel<Orders> model)

{

    var data = order.Where(or => or.OrderID == model.Value.OrderID).FirstOrDefault();

    int affectedRows = 1;

    if (data != null)

    {

        data.OrderID = model.Value.OrderID;

        data.CustomerID = model.Value.CustomerID;

        data.EmployeeID = model.Value.EmployeeID;

        data.OrderDate = model.Value.OrderDate;

        data.ShipCity = model.Value.ShipCity;

        data.Freight = model.Value.Freight;

    }

    return Json(new

    {

        result = model.Value,

        affectedRows = affectedRows, //here we have returned the affected rows count

        error = 0

    });

}

 

Index.cshtml

 

//using the custom adaptor ProcessResponse method, we have received the affected rows count which was returned from the server.

 

class CustomAdaptor extends ej.data.UrlAdaptor {

beforeSend(args, xhr, settings) {

        var newFetchRequest = new Request(settings.url, {

        method: settings.type,

        headers: { 'Content-Type': settings.contentType },

        body: settings.data,

        credentials: 'include',

        });

        settings.fetchRequest = newFetchRequest;

              }

              processQuery(dm, query, hierarchyFilters) {

                             let requestQuery = super.processQuery(dm, query, hierarchyFilters);

                             return requestQuery;

              }

              processResponse(args, _a, _b, _c, ajaxReq) {

                

                             if (args.affectedRows !== undefined) {

                            //here we can access the affected rows count and added this property to the custom adaptor

                             this.noOfAffectedRows = args.affectedRows;

                  }

                         return super.processResponse(args, _a, _b, _c, ajaxReq);

    }

}

 

              let grid = document.getElementById("Grid").ej2_instances[0];

              if (grid) {

                             let dataManager = new ej.data.DataManager({

                                           url: "/Home/UrlDataSource",

                                           insertUrl: "/Home/Insert",

                                           updateUrl: "/Home/Update",

                                           removeUrl: "/Home/Remove",

                                           adaptor: new CustomAdaptor(),

                             });

                             grid.dataSource = dataManager;

              }

});

 

.  .  .  .  .  .  .  .  .

.  .  .  .  .  .  .  .  .

.  .  .  .  .  .  .  .  .

 

function actionComplete(args) {

              if (args.requestType === 'save') {

                             //here we have access the number of affected rows count and notify the user

                             let rows = this.dataSource.adaptor.noOfAffectedRows || 0;

                             alert(rows);

              }

}

function actionFailure(args) {

              console.log('Failure:', args.error);

}


Sample: Check the attachment.

Video demo:




Note
: As requested, we have demonstrated the update action. You can follow a similar approach to handle the insert and delete actions on your end.


Attachment: 196739sample_bd9312ef.zip


PC P Collishaw May 15, 2025 05:24 AM UTC

Thank you for your reply, however I'm afraid I dont understand c# / cshtml files, I am working with javasctipt and php.


I will try and work my way through it and use it as an example, but if you had a .js and .php example, that would be great thank you.




PC P Collishaw May 15, 2025 05:24 AM UTC

Thank you for your reply, however I'm afraid I dont understand c# / cshtml files, I am working with javasctipt and php.


I will try and work my way through it and use it as an example, but if you had a .js and .php example, that would be great thank you.




RR Rajapandi Ravi Syncfusion Team May 16, 2025 11:41 AM UTC

P Collishaw,


Since you are working with JavaScript on the client side and PHP on the server side, you can still achieve the same functionality as our previous C# example by following these key steps:


  1. Customize Your PHP Server Response


In your PHP update endpoint, after updating the data in your database, return a custom JSON response. This response should include:

    • The updated data (result)
    • The number of affected rows (affectedRows)
    • An optional error code (error)

      

public IActionResult Update([FromBody]CRUDModel<Orders> model)

{

    var data = order.Where(or => or.OrderID == model.Value.OrderID).FirstOrDefault();

    int affectedRows = 1;

    if (data != null)

    {

        data.OrderID = model.Value.OrderID;

        data.CustomerID = model.Value.CustomerID;

        data.EmployeeID = model.Value.EmployeeID;

        data.OrderDate = model.Value.OrderDate;

        data.ShipCity = model.Value.ShipCity;

        data.Freight = model.Value.Freight;

    }

    return Json(new

    {

        result = model.Value,

        affectedRows = affectedRows, //here we have returned the affected rows count

        error = 0

    });

}

 


  1. Create a Custom Adaptor in JavaScript


Extend the Syncfusion UrlAdaptor in JavaScript to override the processResponse method. This allows you to extract and store the affectedRows value from the server's response.


class CustomAdaptor extends ej.data.UrlAdaptor {

.  .  .  .  .  .  .  .  .  .

.  .  .  .  .  .  .  .  .  .

.  .  .  .  .  .  .  .  .  .

processResponse(args, _a, _b, _c, ajaxReq) {

                              // Store affected rows to use in actionComplete

                             if (args.affectedRows !== undefined) {

                            //here we can access the affected rows count and added this property to the custom adaptor

                             this.noOfAffectedRows = args.affectedRows;

                  }

                         return super.processResponse(args, _a, _b, _c, ajaxReq);

    }

.  .  .  .  .  .  .  .  .  .

.  .  .  .  .  .  .  .  .  .

 

}


  1. Access the affectedRows in the actionComplete Event


Inside the Grid’s actionComplete event (which triggers after a successful save), you can access the affected rows count from the custom adaptor and display it or use it as needed.


var grid = new ej.grids.Grid({

        dataSource: new ej.data.DataManager({

            url: 'data.php',           // for read

            updateUrl: 'update.php',   // for update

            adaptor: new CustomAdaptor()

        }),

        editSettings: { allowEditing: true, mode: 'Normal' },

        allowPaging: true,

        toolbar: ['Edit', 'Update', 'Cancel'],

        columns: [

            { field: 'OrderID', headerText: 'Order ID', isPrimaryKey: true, width: 120 },

            { field: 'CustomerID', headerText: 'Customer ID', width: 150 },

            { field: 'Freight', headerText: 'Freight', width: 100, editType: 'numericedit' }

        ],

        actionComplete: function(args) {

            if (args.requestType === 'save') {

               //here we have accessed the number of affected rows count and notify the user

                var count = this.dataSource.adaptor.affectedRows || 0;

                alert("Updated rows: " + count);

            }

        },

        actionFailure: function(args) {

            console.error("Update failed:", args.error);

        }

    });

 

    grid.appendTo('#Grid');


By following this approach, you can handle the insert and delete actions on your end also you can maintain full control over the server's response and keep the Grid behavior consistent. This also allows you to display messages to users based on the result of their actions (e.g., how many rows were updated).


Loader.
Up arrow icon