- Home
- Forum
- ASP.NET Core - EJ 2
- How to refresh only the data that changed after edit?
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();
}
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.
- 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 - 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
- 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.
- 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?
- 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.
- Version Details: Share your Syncfusion NuGet package and script version.
- 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.
Sivaranjani R
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.
- 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.
- Find my code below. At this moment, I'm only testing with editing rows.
- 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.
- 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.
- Syncfusion.EJ2.AspNET.Core 28.2.11
- I have attached some images.
@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>
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; }
}
actionComplete event, which triggers after an action is completed. Additionally, calling populateGridData again results in refetching all data unnecessarily.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.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); } }); }); |
- If there are new records in
batchOperation.Added, they are inserted intoorddata.
- If there are changes in
batchOperation.Changed, the corresponding records inorddataare updated based onOrderID
- If records are deleted in
batchOperation.Deleted, they are removed fromorddata
- 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()); } |
- No unnecessary data refetching – Only modified data is sent to the server.
- Efficient updates – The batch URL ensures that only edited rows are updated, rather than refetching the entire dataset.
- Optimized performance – Since all other operations (filtering, sorting, pagination) are handled on the client side, server load is minimized.
Attachment: RemoteSaveAdaptor_88c0d5b1.zip
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.
- 6 Replies
- 2 Participants
-
LL Lukas Lapinskas
- Mar 13, 2025 07:02 PM UTC
- Mar 20, 2025 06:52 AM UTC