How to refresh only the data that changed after edit?

I have a grid component which implements bulk editing with autofill enabled. I also have controller actions that handle getting the data and processing the edits.

I noticed that after I make an edit, let's say I autofill 2 rows, the component calls the Get controller action and retrieves all rows again. I'd expect the component to only update the two rows that changed instead of retrieving all the rows. This adds unnecessary database calls and time to update the data. I don't want it to potentially retrieve again thousands of rows just because I updated one or two cells. 

Is there a way to have the grid only update what was marked to be updated on the client side?

I attempted to do this by returning value.changed from the Edit action, but it doesn't work because after that the component calls the Get again to get all the data:


    public IActionResult Edit([FromBody] CRUDModel<NedaRow> value)

    {

        var order = value.value;

        if (value.action == "update")

            return Json(value.value);

            // perform sql call to update


        if (value.action == "batch")

            // perform sql call to update

            return Json(value.changed);


        return BadRequest();

    }


6 Replies

LL Lukas Lapinskas March 13, 2025 08:12 PM UTC

Just an update, one potential solution I found is to add server-side paging. So, if I update a single cell, it only needs to refetch all of the first page's data instead of all data.

However, I don't want to do server-side paging and want to load all the data upfront, so this isn't solving my problem yet.



SR Sivaranjani Rajasekaran Syncfusion Team March 17, 2025 04:15 PM UTC

Hi Lukas Lapinskas,

Greetings from Syncfusion support!
Based on your query it appears that you want to refresh only the data that changed after edit. Before we start providing solution to your query, we need some additional information for our clarification. Please share the following information:
  1. Data Adaptor: In Syncfusion Grid remote data binding, various adaptors like UrlAdaptor, WebApiAdaptor, etc., are available. We have already documented how to connect these adaptors in our documentation. Please refer to the link  Documentation Link   
    1. In this Which data adaptor are you using? Please share the details of your adaptor, or if you are implementing custom logic, kindly share those details as well
  2. Grid Configuration:  Share your complete Grid rendering code (client and server-side), so that we can review your initialization settings, implemented features, and how your backend is configured.
  3. Expected Behavior: In your query you have mentioned that you do not want to re-fetch all rows after an update. Could you please confirm you are looking to update the modified data only on the client side without making a server request?
  4. Server-Side Paging: You noted that server-side paging helps reduce unnecessary data fetching. In Syncfusion, the RemoteSaveAdaptor enhances performance by minimizing server interactions. Do you have a specific reason for loading all data upfront? Please share your exact requirements and use case details.
  5. Version Details: Share your Syncfusion NuGet package and script version.
  6. Payload Information : Could you please share a screenshot or a video recording of the Network tab in your browser's developer tools? This should capture the request being sent to the server when performing an action in the grid, that including the request URL, headers, payload, and response, are visible. This will help us analyze the issue more effectively.
Once I have these details, we can suggest the best approach.

Looking forward to your response!

Regards,

Sivaranjani R



LL Lukas Lapinskas March 17, 2025 06:09 PM UTC

Thanks for the response, Sivaranjani. To be clear, I want to be able to for the grid to do the following things:

  • Initially load data through url (ajax) and not through view model.
  • Add, edit, delete rows on server side by calling controller actions.
  • After these modifications, update that data both on client side and server side without needing to refetch unchanged records.
  • All other actions, such as search, paginating, column ordering, etc. happen on client-side.
The only requirement I'm left to meet is to not refetch unchanged records after an update.

To answer your questions:
  1. At this moment I have remoteSaveAdaptor.  This is set in an ajax function I needed to write to try and meet some of my requirements.
  2. Find my code below. At this moment, I'm only testing with editing rows.
  3. Let me be clearer about what I want. I want the modified data to be updated on the client side and in the server (which requires reaching out to the server). But I don't want the component to reach out to the server in order to retrieve all of the data again. That shouldn't be necessary if the modification went through successfully and the client-side data has already changed.
  4. Yes, I have a specific reason to load all data upfront. The reason is because if I load data using server-side, that means not only do I have to write code to add pagination, but now I am also forced to write code for filtering data and sorting it. I don't want to write all that code and instead leave it up to the client-side to handle it.
  5.  Syncfusion.EJ2.AspNET.Core 28.2.11
  6. I have attached some images.









Code:
View:

@section Scripts {

    <script>

        $(document).ready(function(){

            populateGridData();

        });


        function actionComplete(args) {

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

                populateGridData()

            }

        }


        function populateGridData() {

            var grid = document.getElementById('js-grid').ej2_instances[0];

            $.ajax({

                url: '/NedaFormatEditor/Get',

                type: 'GET',

            }).done(function(data) {

                var dataSource = new ej.data.DataManager({

                    json: data,

                    adaptor: new ej.data.RemoteSaveAdaptor(),

                    batchUrl: "/NedaFormatEditor/Edit",

                    updateUrl: '/NedaFormatEditor/Edit',

                });

                grid.dataSource = dataSource;

            });

        }

    </script>

}


<h1>NEDA-type Data</h1>

<input type="button" value="Rerun" class="btn btn-primary" />


<ejs-grid id="js-grid" actionComplete="actionComplete" allowFiltering="true" allowPaging="true" enableAutoFill="true" allowSelection="true" toolbar="@(new List<string>() { "Edit", "Update", "Cancel" })">

    <e-grid-editSettings allowEditing="true" mode="Batch" showConfirmDialog="true"></e-grid-editSettings>

    <e-grid-selectionsettings mode="Cell" type="Multiple"></e-grid-selectionsettings>

    <e-grid-columns>

        <e-grid-column field="NedaRowID" headerText="Neda Row ID" validationRules="@(new { required=true })" isPrimaryKey="true"></e-grid-column>

        <e-grid-column field="CustomerID" headerText="Customer Name" validationRules="@(new { required=true })"></e-grid-column>

    </e-grid-columns>

</ejs-grid>


Controller:

using Microsoft.AspNetCore.Mvc;

using System.Data;


namespace ProcessData.WebUI.Features.NedaFormatEditor;


public class NedaFormatEditorController : Controller

{

    public IActionResult Index(int pipelineRunId)

    {

        // TODO viewModel to store and pass int pipelineRunId to Get action

        return View("NedaFormatEditor");

    }


    public IActionResult Get(int pipelineRunId)

    {

        var items = new List<NedaRow>();


        int code = 10000;

        for (int i = 1; i < 5; i++)

        {

            items.Add(new NedaRow

            {

                NedaRowID = code + 1,

                CustomerID = "ALFKI",

                EmployeeID = i + 0,

                Freight = 2.3 * i,

                ShipCity = "Berlin",

                NedaDate = new DateTime(1991, 05, 15)

            });

            items.Add(new NedaRow

            {

                NedaRowID = code + 2,

                CustomerID = "ANATR",

                EmployeeID = i + 2,

                Freight = 3.3 * i,

                ShipCity = "Madrid",

                NedaDate = new DateTime(1990, 04, 04)

            });

            items.Add(new NedaRow

            {

                NedaRowID = code + 3,

                CustomerID = "ANTON",

                EmployeeID = i + 1,

                Freight = 4.3 * i,

                ShipCity = "Cholchester",

                NedaDate = new DateTime(1957, 11, 30)

            });

            items.Add(new NedaRow

            {

                NedaRowID = code + 4,

                CustomerID = "BLONP",

                EmployeeID = i + 3,

                Freight = 5.3 * i,

                ShipCity = "Marseille",

                NedaDate = new DateTime(1930, 10, 22)

            });

            items.Add(new NedaRow

            {

                NedaRowID = code + 5,

                CustomerID = "BOLID",

                EmployeeID = i + 4,

                Freight = 6.3 * i,

                ShipCity = "Tsawassen",

                NedaDate = new DateTime(1953, 02, 18)

            });

            code += 5;

        }


        //TODO get neda rows from db.

        return Json(items);

    }


    public IActionResult Edit([FromBody] CRUDModel<NedaRow> value)

    {

        var order = value.value;

        if (value.action == "update")

            return Json(value.value);


        if (value.action == "batch")

        {

// TODO perform sql call to update

        }


        return BadRequest();

    }

}


public class NedaRow

{

    public int NedaRowID { get; set; }

    public string CustomerID { get; set; }

    public int? EmployeeID { get; set; }

    public double? Freight { get; set; }

    public string ShipCity { get; set; }

    public DateTime NedaDate { get; set; }

}


public class CRUDModel<T> where T : class

{

    public string action { get; set; }


    public string table { get; set; }


    public string keyColumn { get; set; }


    public object key { get; set; }


    public T value { get; set; }


    public List<T> added { get; set; }


    public List<T> changed { get; set; }


    public List<T> deleted { get; set; }


    public IDictionary<string, object> @params { get; set; }

}



SR Sivaranjani Rajasekaran Syncfusion Team March 19, 2025 11:22 AM UTC

Hi Lukas Lapinskas,

Thank you for sharing details.

After reviewing your requirements, we understand that you want to perform CRUD operations on the server side while keeping all other actions (such as filtering, sorting, and pagination) on the client side. Additionally, you want to avoid unnecessary server calls and prevent refetching all records after an update. Based on your needs, RemoteSaveAdaptor is the suitable option.
Upon reviewing your code, we noticed that batch editing is not handled properly. Currently, you are calling the API inside the actionComplete event, which triggers after an action is completed. Additionally, calling populateGridData again results in refetching all data unnecessarily.
To resolve this issue, you can bind the batchUrl directly in the grid’s dataSource. This ensures that when batch updates are triggered, the batchUrl will send the changes to the server without refetching all the data.
Please refer to the code below for more information:

[client side]

Code Example : 

 $(document).ready(function () {
         $.ajax({
             url: "/Home/GetOrders", // API Endpoint
             type: "GET",
             dataType: "json",
             success: function (data) {
                 var grid = document.getElementById("Grid").ej2_instances[0]; // Get Grid Instance
                  var dataSource = new ej.data.DataManager({
                     json: data,
                     adaptor: new ej.data.RemoteSaveAdaptor(),
                     batchUrl: "/Home/Batch",

                 });
                 grid.dataSource = dataSource;// Assign Data to Grid
             },
            error: function (error) {
                 console.log("Error fetching data:", error);
             }
         });
     });

Server side : 

The following implementation ensures that only modified data (added, changed, or deleted) is updated on the server without refetching all records.

1. Handling Added Records:
  • If there are new records in batchOperation.Added, they are inserted into orddata.
2. Handling Edited Records:
  • If there are changes in batchOperation.Changed, the corresponding records in orddata are updated based on OrderID
3. Handling Deleted Records:
  • If records are deleted in batchOperation.Deleted, they are removed from orddata
4. Returning Updated Data:
  • The response includes all the modified records (added, changed, deleted).
  • This ensures that the grid updates only the modified data without re-fetching all records.

[HomerController.cs]

 public IActionResult Batch([FromBody] CRUDModel<OrdersDetails> batchOperation)
    {
        if (batchOperation.Added != null)
        {
          foreach (var addedOrder in batchOperation.Added)
          {
            orddata.Insert(0, addedOrder);
          }
        }
        if (batchOperation.Changed != null)
          {
            foreach (var changedOrder in batchOperation.Changed)
            {
              var existingOrder = orddata.FirstOrDefault(or => or.OrderID == changedOrder.OrderID);
              if (existingOrder != null)
              {
                existingOrder.CustomerID = changedOrder.CustomerID;
                existingOrder.ShipCity = changedOrder.ShipCity;  
                // Update other properties as needed
              }
            }
        }
      if (batchOperation.Deleted != null)
        {
          foreach (var deletedOrder in batchOperation.Deleted)
          {
            var orderToDelete = orddata.FirstOrDefault(or => or.OrderID == deletedOrder.OrderID);
            if (orderToDelete != null)
            {
              orddata.Remove(orderToDelete);
            }
          }
        }
           return new JsonResult(new {
            added = batchOperation.Added,
            changed = batchOperation.Changed,
            deleted = batchOperation.Deleted
        }, new Newtonsoft.Json.JsonSerializerSettings());
    }

Key Benefits of This Approach
  1. No unnecessary data refetching – Only modified data is sent to the server.
  2. Efficient updates – The batch URL ensures that only edited rows are updated, rather than refetching the entire dataset.
  3. Optimized performance – Since all other operations (filtering, sorting, pagination) are handled on the client side, server load is minimized.
Sample : Please find the sample attached.

Video Demo:


Please get back to us if you need further assistance.



Attachment: RemoteSaveAdaptor_88c0d5b1.zip


LL Lukas Lapinskas replied to Sivaranjani Rajasekaran March 19, 2025 09:15 PM UTC

Sivaranjani, thank you for contributing the attachment. I was able to implement it successfully into my application.

I actually have tried doing it this way before but it did not work. It took many hours to figure out why your sample code works and why mine did not. I tried all kinds of things but I was finally able to figure out. 

The issue for me was that the value in the field ​attribute on <e-grid-column>​ tag for the primary key started with a capital character. Once I lowercased it, it worked. 



SR Sivaranjani Rajasekaran Syncfusion Team March 20, 2025 06:52 AM UTC


Thanks for the update! Please get back to us if you need further assistance.

Loader.
Up arrow icon