DataSource and Editing
The DataSource is Kendo's client-side data layer: it fetches, tracks changes, and syncs back to your controller. Once you configure its CRUD endpoints, the grid becomes an editor, not just a viewer β which is exactly how most internal agency tools are built.
Three edit modes
- Inline (
Editable(e => e.Mode(GridEditMode.InLine))) β the row turns into editors; Save/ Cancel per row. The safe default for row-at-a-time updates. - Popup (
GridEditMode.PopUp) β opens a window, optionally with a custom editor template (.TemplateName("PermitEditor")), good when the form is bigger than the grid columns. - Batch / InCell (
GridEditMode.InCellwith.Batch(true)) β spreadsheet-style: users edit many cells, then one Save button syncs all creates/updates/deletes together. Fast for power users, but hardest to reason about server-side.
Each mode uses the same DataSource contract: .Read(), .Create(), .Update(), .Destroy()
actions, plus a model definition telling Kendo the identity and any read-only fields:
.Model(m => { m.Id(p => p.PermitId); m.Field(p => p.Number).Editable(false); })
Forget m.Id(...) and editing silently misbehaves β updates arrive as creates, rows duplicate.
It's the first thing to check when editing "doesn't work."
Validation that round-trips
Kendo reads DataAnnotations ([Required], [StringLength], [Range]) from the view model
and enforces them client-side in the editors. But client validation is UX, not security β your
update action must re-validate and report failures back through the DataSource:
if (!ModelState.IsValid)
return Json(new[] { vm }.ToDataSourceResult(request, ModelState));
Passing ModelState puts the errors into the response's Errors collection. Handle it with a
DataSource .Events(e => e.Error("onGridError")) handler that displays the messages and
calls grid.dataSource.cancelChanges() (or keeps the cell dirty) β otherwise the grid happily
pretends the save succeeded. Wiring this error handler is non-optional; teams that skip it ship
grids that silently drop failed saves.
Concurrency basics
Two clerks open the same record; both save. Last-write-wins is rarely acceptable in government
work. The standard pattern: carry a rowversion (timestamp) field in the row view model,
include it in the update payload, and let EF's optimistic concurrency check reject stale writes
(Module 5 covers the mechanics). On DbUpdateConcurrencyException, add a friendly message to
ModelState ("This record was changed by someone else β reload and retry") and return it via
the Errors path above. The grid's error event then tells the user why, and a
dataSource.read() refreshes to current data. Predictable, auditable, and no lost updates.