From 5b4b8f5d87db2fc76abc34b30e1925b12bfe9077 Mon Sep 17 00:00:00 2001 From: Dimo Dimov <961014+dimodi@users.noreply.github.com> Date: Fri, 31 Jan 2025 14:58:05 +0200 Subject: [PATCH 01/33] docs(Grid): Revamp Editing articles --- components/grid/editing/incell.md | 277 +++++++++++++++++++--------- components/grid/editing/inline.md | 290 +++++++++++++++++++---------- components/grid/editing/popup.md | 296 ++++++++++++++++++++---------- 3 files changed, 585 insertions(+), 278 deletions(-) diff --git a/components/grid/editing/incell.md b/components/grid/editing/incell.md index 1bc7ed992..0db71d60b 100644 --- a/components/grid/editing/incell.md +++ b/components/grid/editing/incell.md @@ -38,152 +38,249 @@ It is up to the data access logic to save the data once it is changed in the dat >caption Incell Editing Example. See the code comments for details. ````RAZOR -@using System.ComponentModel.DataAnnotations @* for the validation attributes *@ - -Click a cell, edit it and click outside of the grid to see the change. You can also use Tab, Shift+Tab and Enter to navigate between the cells. -
-Editing is prevented for the first two items. - - +@using System.ComponentModel.DataAnnotations +@using Telerik.DataSource +@using Telerik.DataSource.Extensions + +

The example below shows how to:

+ + + + - Add Employee + Add Item + + + + - - - - - Delete + + + + + + + + @{ var dataItem = (Product)context; } + @if (dataItem.Discontinued) + { + Delete + } @code { - void EditHandler(GridCommandEventArgs args) - { - SampleData item = (SampleData)args.Item; - - // prevent opening for edit based on condition - if (item.ID < 3) - { - args.IsCancelled = true;// the general approach for cancelling an event - } + private List GridData { get; set; } = new(); - Console.WriteLine("Edit event is fired."); - } + private ProductService GridProductService { get; set; } = new(); - async Task UpdateHandler(GridCommandEventArgs args) - { - SampleData item = (SampleData)args.Item; + [CascadingParameter] + public DialogFactory? TelerikDialogs { get; set; } - // perform actual data source operations here through your service - await MyService.Update(item); + private bool GridConfirmDelete { get; set; } = true; + private bool ShouldCancelOnAddEdit { get; set; } + private bool ShouldConfirmOnCancel { get; set; } = true; - // update the local view-model data with the service data - await GetGridData(); + private string AddEditButtonThemeColor => ShouldCancelOnAddEdit ? ThemeConstants.Button.ThemeColor.Error : ThemeConstants.Button.ThemeColor.Base; + private string DeleteButtonThemeColor => GridConfirmDelete ? ThemeConstants.Button.ThemeColor.Base : ThemeConstants.Button.ThemeColor.Warning; + private string CancelButtonThemeColor => ShouldConfirmOnCancel ? ThemeConstants.Button.ThemeColor.Base : ThemeConstants.Button.ThemeColor.Warning; - Console.WriteLine("Update event is fired."); + private void OnGridAdd(GridCommandEventArgs args) + { + if (ShouldCancelOnAddEdit) + { + args.IsCancelled = true; + return; + } } - async Task DeleteHandler(GridCommandEventArgs args) + private async Task OnGridCancel(GridCommandEventArgs args) { - SampleData item = (SampleData)args.Item; - - // perform actual data source operation here through your service - await MyService.Delete(item); - - // update the local view-model data with the service data - await GetGridData(); + if (ShouldConfirmOnCancel) + { + bool shouldContinue = await TelerikDialogs!.ConfirmAsync("Do you want to discard your changes?"); - Console.WriteLine("Delete event is fired."); + if (!shouldContinue) + { + args.IsCancelled = true; + } + } } - async Task CreateHandler(GridCommandEventArgs args) + private async Task OnGridCreate(GridCommandEventArgs args) { - SampleData item = (SampleData)args.Item; - - // perform actual data source operation here through your service - await MyService.Create(item); + var createdItem = (Product)args.Item; - // update the local view-model data with the service data - await GetGridData(); + // Create the item in the database. + int newId = await GridProductService.Create(createdItem); - Console.WriteLine("Create event is fired."); + // Reload the data from the database. + GridData = await GridProductService.Read(); + // OR + // Create the item in the local data too. + //createdItem.Id = newId; + //GridData.Insert(0, createdItem); } - void OnCancelHandler(GridCommandEventArgs args) + private async Task OnGridDelete(GridCommandEventArgs args) { - SampleData item = (SampleData)args.Item; - Console.WriteLine("Cancel event is fired. Can be useful when people decide to not satisfy validation"); - } + var deletedItem = (Product)args.Item; + // Delete the item in the database. + await GridProductService.Delete(deletedItem); - // in a real case, keep the models in dedicated locations, this is just an easy to copy and see example - public class SampleData - { - public int ID { get; set; } - [Required] - public string FirstName { get; set; } - public string LastName { get; set; } + // Reload the data from the database. + GridData = await GridProductService.Read(); + // OR + // Delete the item in the local data too. + //GridData.Remove(deletedItem); } - public List MyData { get; set; } + private void OnGridEdit(GridCommandEventArgs args) + { + if (ShouldCancelOnAddEdit) + { + args.IsCancelled = true; + return; + } + } - async Task GetGridData() + private async Task OnGridUpdate(GridCommandEventArgs args) { - MyData = await MyService.Read(); + var updatedItem = (Product)args.Item; + + // Update the item in the database. + bool success = await GridProductService.Update(updatedItem); + + // Reload the data from the database. + GridData = await GridProductService.Read(); + // OR + // Update the item in the local data too. + //int originalItemIndex = GridData.FindIndex(i => i.Id == updatedItem.Id); + //if (originalItemIndex != -1) + //{ + // GridData[originalItemIndex] = updatedItem; + //} } protected override async Task OnInitializedAsync() { - await GetGridData(); + GridData = await GridProductService.Read(); } - // the following static class mimics an actual data service that handles the actual data source - // replace it with your actual service through the DI, this only mimics how the API can look like and works for this standalone page - public static class MyService + public class ProductService { - private static List _data { get; set; } = new List(); + private List Items { get; set; } - public static async Task Create(SampleData itemToInsert) + private int LastId { get; set; } + + public async Task Create(Product product) { - itemToInsert.ID = _data.Count + 1; - _data.Insert(0, itemToInsert); + // Simulate async operation. + await Task.Delay(100); + + product.Id = ++LastId; + + Items.Insert(0, product); + + return LastId; } - public static async Task> Read() + public async Task Delete(Product product) { - if (_data.Count < 1) + // Simulate async operation. + await Task.Delay(100); + + if (Items.Contains(product)) { - for (int i = 1; i < 50; i++) - { - _data.Add(new SampleData() - { - ID = i, - FirstName = "Name " + i.ToString(), - LastName = "Last Name " + i.ToString() - }); - } + Items.Remove(product); + + return true; } - return await Task.FromResult(_data); + return false; + } + + public async Task> Read() + { + // Simulate async operation. + await Task.Delay(100); + + return Items; + } + + public async Task Read(DataSourceRequest request) + { + return await Items.ToDataSourceResultAsync(request); } - public static async Task Update(SampleData itemToUpdate) + public async Task Update(Product product) { - var index = _data.FindIndex(i => i.ID == itemToUpdate.ID); - if (index != -1) + // Simulate async operation. + await Task.Delay(100); + + int originalItemIndex = Items.FindIndex(x => x.Id == product.Id); + + if (originalItemIndex != -1) { - _data[index] = itemToUpdate; + Items[originalItemIndex] = product; + return true; } + + return false; } - public static async Task Delete(SampleData itemToDelete) + public ProductService() { - _data.Remove(itemToDelete); + Items = new(); + + for (int i = 1; i <= 15; i++) + { + Items.Add(new Product() + { + Id = ++LastId, + Name = $"Product {LastId}", + Description = $"Multi-line\ndescription {LastId}", + Price = LastId % 2 == 0 ? null : Random.Shared.Next(0, 100) * 1.23m, + Quantity = LastId % 2 == 0 ? 0 : Random.Shared.Next(0, 3000), + ReleaseDate = DateTime.Today.AddDays(-Random.Shared.Next(365, 3650)), + Discontinued = LastId % 2 == 0 + }); + } + } } + + public class Product + { + public int Id { get; set; } + [Required] + public string Name { get; set; } = string.Empty; + public string Description { get; set; } = string.Empty; + public decimal? Price { get; set; } + public int Quantity { get; set; } + [Required] + public DateTime? ReleaseDate { get; set; } + public bool Discontinued { get; set; } + } } ```` diff --git a/components/grid/editing/inline.md b/components/grid/editing/inline.md index 1edc97287..bd5f868d2 100644 --- a/components/grid/editing/inline.md +++ b/components/grid/editing/inline.md @@ -20,159 +20,265 @@ You can also cancel the events by setting the `IsCancelled` property of the even To enable Inline editing in the grid, set its `EditMode` property to `Telerik.Blazor.GridEditMode.Inline`, then handle the CRUD events as shown in the example below. - >caption The Command buttons and the grid events let you handle data operations in Inline edit mode (see the code comments for details) ````RAZOR -@using System.ComponentModel.DataAnnotations @* for the validation attributes *@ - -Use the command buttons to control the CUD operations. -
-Editing is cancelled for the first two records. - - +@using System.ComponentModel.DataAnnotations +@using Telerik.DataSource +@using Telerik.DataSource.Extensions + +

The example below shows how to:

+ +
    +
  • Render command buttons conditionally.
  • +
  • Refresh the Grid after editing by reloading the data from the remote datasource.
  • +
  • Refresh the Grid after editing by applying the user changes to the local data collection.
  • +
  • Cancel the OnCancel event conditionally, so that the Grid remains in edit mode. Similar behavior can be achieved by cancelling OnCreate and OnUpdate.
  • +
  • Confirm Delete commands with a built-in Grid dialog. You can also intercept Delete commands with a separate Dialog or a custom popup.
  • +
  • Cancel the OnAdd and OnEdit events conditionally, so that the Grid does not go into edit mode.
  • +
+ + - Add Employee + Add Item + + + + + + - - - - Save - Edit - Delete - Cancel + + + + + + + + + + + @{ var dataItem = (Product)context; } + Edit + Save + Cancel + @if (dataItem.Discontinued) + { + Delete + } @code { - void EditHandler(GridCommandEventArgs args) - { - SampleData item = (SampleData)args.Item; - - // prevent opening for edit based on condition - if (item.ID < 3) - { - args.IsCancelled = true;// the general approach for cancelling an event - } + private List GridData { get; set; } = new(); - Console.WriteLine("Edit event is fired."); - } + private ProductService GridProductService { get; set; } = new(); - async Task UpdateHandler(GridCommandEventArgs args) - { - SampleData item = (SampleData)args.Item; + [CascadingParameter] + public DialogFactory? TelerikDialogs { get; set; } - // perform actual data source operations here through your service - await MyService.Update(item); + private bool GridConfirmDelete { get; set; } = true; + private bool ShouldCancelOnAddEdit { get; set; } + private bool ShouldConfirmOnCancel { get; set; } = true; - // update the local view-model data with the service data - await GetGridData(); + private string AddEditButtonThemeColor => ShouldCancelOnAddEdit ? ThemeConstants.Button.ThemeColor.Error : ThemeConstants.Button.ThemeColor.Base; + private string DeleteButtonThemeColor => GridConfirmDelete ? ThemeConstants.Button.ThemeColor.Base : ThemeConstants.Button.ThemeColor.Warning; + private string CancelButtonThemeColor => ShouldConfirmOnCancel ? ThemeConstants.Button.ThemeColor.Base : ThemeConstants.Button.ThemeColor.Warning; - Console.WriteLine("Update event is fired."); + private void OnGridAdd(GridCommandEventArgs args) + { + if (ShouldCancelOnAddEdit) + { + args.IsCancelled = true; + return; + } } - async Task DeleteHandler(GridCommandEventArgs args) + private async Task OnGridCancel(GridCommandEventArgs args) { - SampleData item = (SampleData)args.Item; - - // perform actual data source operation here through your service - await MyService.Delete(item); - - // update the local view-model data with the service data - await GetGridData(); + if (ShouldConfirmOnCancel) + { + bool shouldContinue = await TelerikDialogs!.ConfirmAsync("Do you want to discard your changes?"); - Console.WriteLine("Delete event is fired."); + if (!shouldContinue) + { + args.IsCancelled = true; + } + } } - async Task CreateHandler(GridCommandEventArgs args) + private async Task OnGridCreate(GridCommandEventArgs args) { - SampleData item = (SampleData)args.Item; - - // perform actual data source operation here through your service - await MyService.Create(item); + var createdItem = (Product)args.Item; - // update the local view-model data with the service data - await GetGridData(); + // Create the item in the database. + int newId = await GridProductService.Create(createdItem); - Console.WriteLine("Create event is fired."); + // Reload the data from the database. + GridData = await GridProductService.Read(); + // OR + // Create the item in the local data too. + //createdItem.Id = newId; + //GridData.Insert(0, createdItem); } - async Task CancelHandler(GridCommandEventArgs args) + private async Task OnGridDelete(GridCommandEventArgs args) { - SampleData item = (SampleData)args.Item; + var deletedItem = (Product)args.Item; - // if necessary, perform actual data source operation here through your service + // Delete the item in the database. + await GridProductService.Delete(deletedItem); - Console.WriteLine("Cancel event is fired."); + // Reload the data from the database. + GridData = await GridProductService.Read(); + // OR + // Delete the item in the local data too. + //GridData.Remove(deletedItem); } - - // in a real case, keep the models in dedicated locations, this is just an easy to copy and see example - public class SampleData + private void OnGridEdit(GridCommandEventArgs args) { - public int ID { get; set; } - [Required] - public string Name { get; set; } + if (ShouldCancelOnAddEdit) + { + args.IsCancelled = true; + return; + } } - public List MyData { get; set; } - - async Task GetGridData() + private async Task OnGridUpdate(GridCommandEventArgs args) { - MyData = await MyService.Read(); + var updatedItem = (Product)args.Item; + + // Update the item in the database. + bool success = await GridProductService.Update(updatedItem); + + // Reload the data from the database. + GridData = await GridProductService.Read(); + // OR + // Update the item in the local data too. + //int originalItemIndex = GridData.FindIndex(i => i.Id == updatedItem.Id); + //if (originalItemIndex != -1) + //{ + // GridData[originalItemIndex] = updatedItem; + //} } protected override async Task OnInitializedAsync() { - await GetGridData(); + GridData = await GridProductService.Read(); } - // the following static class mimics an actual data service that handles the actual data source - // replace it with your actual service through the DI, this only mimics how the API can look like and works for this standalone page - public static class MyService + public class ProductService { - private static List _data { get; set; } = new List(); + private List Items { get; set; } + + private int LastId { get; set; } - public static async Task Create(SampleData itemToInsert) + public async Task Create(Product product) { - itemToInsert.ID = _data.Count + 1; - _data.Insert(0, itemToInsert); + // Simulate async operation. + await Task.Delay(100); + + product.Id = ++LastId; + + Items.Insert(0, product); + + return LastId; } - public static async Task> Read() + public async Task Delete(Product product) { - if (_data.Count < 1) + // Simulate async operation. + await Task.Delay(100); + + if (Items.Contains(product)) { - for (int i = 1; i < 50; i++) - { - _data.Add(new SampleData() - { - ID = i, - Name = "Name " + i.ToString() - }); - } + Items.Remove(product); + + return true; } - return await Task.FromResult(_data); + return false; + } + + public async Task> Read() + { + // Simulate async operation. + await Task.Delay(100); + + return Items; + } + + public async Task Read(DataSourceRequest request) + { + return await Items.ToDataSourceResultAsync(request); } - public static async Task Update(SampleData itemToUpdate) + public async Task Update(Product product) { - var index = _data.FindIndex(i => i.ID == itemToUpdate.ID); - if (index != -1) + // Simulate async operation. + await Task.Delay(100); + + int originalItemIndex = Items.FindIndex(x => x.Id == product.Id); + + if (originalItemIndex != -1) { - _data[index] = itemToUpdate; + Items[originalItemIndex] = product; + return true; } + + return false; } - public static async Task Delete(SampleData itemToDelete) + public ProductService() { - _data.Remove(itemToDelete); + Items = new(); + + for (int i = 1; i <= 15; i++) + { + Items.Add(new Product() + { + Id = ++LastId, + Name = $"Product {LastId}", + Description = $"Multi-line\ndescription {LastId}", + Price = LastId % 2 == 0 ? null : Random.Shared.Next(0, 100) * 1.23m, + Quantity = LastId % 2 == 0 ? 0 : Random.Shared.Next(0, 3000), + ReleaseDate = DateTime.Today.AddDays(-Random.Shared.Next(365, 3650)), + Discontinued = LastId % 2 == 0 + }); + } + } } + + public class Product + { + public int Id { get; set; } + [Required] + public string Name { get; set; } = string.Empty; + public string Description { get; set; } = string.Empty; + public decimal? Price { get; set; } + public int Quantity { get; set; } + [Required] + public DateTime? ReleaseDate { get; set; } + public bool Discontinued { get; set; } + } } ```` diff --git a/components/grid/editing/popup.md b/components/grid/editing/popup.md index ff91e5b79..b9554795d 100644 --- a/components/grid/editing/popup.md +++ b/components/grid/editing/popup.md @@ -36,160 +36,264 @@ The Popup editing mode supports [validation](slug:common-features/input-validati ````RAZOR @using System.ComponentModel.DataAnnotations - -Editing is cancelled for the fifth item conditionally. - - +@using Telerik.DataSource +@using Telerik.DataSource.Extensions + +

The example below shows how to:

+ +
    +
  • Customize the popup edit form dimensions and layout.
  • +
  • Render command buttons conditionally.
  • +
  • Refresh the Grid after editing by reloading the data from the remote datasource.
  • +
  • Refresh the Grid after editing by applying the user changes to the local data collection.
  • +
  • Cancel the OnCancel event conditionally, so that the Grid remains in edit mode. Similar behavior can be achieved by cancelling OnCreate and OnUpdate.
  • +
  • Confirm Delete commands with a built-in Grid dialog. You can also intercept Delete commands with a separate Dialog or a custom popup.
  • +
  • Cancel the OnAdd and OnEdit events conditionally, so that the Grid does not go into edit mode.
  • +
+ + + + + + - Add Employee + Add Item + + + + + + - - - - - - Edit - Delete + + + + + + + + + + + @{ var dataItem = (Product)context; } + Edit + @if (dataItem.Discontinued) + { + Delete + } @code { - private void EditHandler(GridCommandEventArgs args) - { - SampleData item = (SampleData)args.Item; - - // prevent opening for edit based on condition - if (item.ID == 8) - { - args.IsCancelled = true;// the general approach for cancelling an event - } + private List GridData { get; set; } = new(); - Console.WriteLine("Edit event is fired."); - } + private ProductService GridProductService { get; set; } = new(); - private async Task UpdateHandler(GridCommandEventArgs args) - { - SampleData item = (SampleData)args.Item; + [CascadingParameter] + public DialogFactory? TelerikDialogs { get; set; } - // perform actual data source operations here through your service - await MyService.Update(item); + private bool GridConfirmDelete { get; set; } = true; + private bool ShouldCancelOnAddEdit { get; set; } + private bool ShouldConfirmOnCancel { get; set; } = true; - // update the local view-model data with the service data - await GetGridData(); + private string AddEditButtonThemeColor => ShouldCancelOnAddEdit ? ThemeConstants.Button.ThemeColor.Error : ThemeConstants.Button.ThemeColor.Base; + private string DeleteButtonThemeColor => GridConfirmDelete ? ThemeConstants.Button.ThemeColor.Base : ThemeConstants.Button.ThemeColor.Warning; + private string CancelButtonThemeColor => ShouldConfirmOnCancel ? ThemeConstants.Button.ThemeColor.Base : ThemeConstants.Button.ThemeColor.Warning; - Console.WriteLine("Update event is fired."); + private void OnGridAdd(GridCommandEventArgs args) + { + if (ShouldCancelOnAddEdit) + { + args.IsCancelled = true; + return; + } } - private async Task DeleteHandler(GridCommandEventArgs args) + private async Task OnGridCancel(GridCommandEventArgs args) { - SampleData item = (SampleData)args.Item; - - // perform actual data source operation here through your service - await MyService.Delete(item); - - // update the local view-model data with the service data - await GetGridData(); + if (ShouldConfirmOnCancel) + { + bool shouldContinue = await TelerikDialogs!.ConfirmAsync("Do you want to discard your changes?"); - Console.WriteLine("Delete event is fired."); + if (!shouldContinue) + { + args.IsCancelled = true; + } + } } - private async Task CreateHandler(GridCommandEventArgs args) + private async Task OnGridCreate(GridCommandEventArgs args) { - SampleData item = (SampleData)args.Item; + var createdItem = (Product)args.Item; - // perform actual data source operation here through your service - await MyService.Create(item); + // Create the item in the database. + int newId = await GridProductService.Create(createdItem); - // update the local view-model data with the service data - await GetGridData(); - - Console.WriteLine("Create event is fired."); + // Reload the data from the database. + GridData = await GridProductService.Read(); + // OR + // Create the item in the local data too. + //createdItem.Id = newId; + //GridData.Insert(0, createdItem); } - private async Task CancelHandler(GridCommandEventArgs args) + private async Task OnGridDelete(GridCommandEventArgs args) { - SampleData item = (SampleData)args.Item; + var deletedItem = (Product)args.Item; - // if necessary, perform actual data source operation here through your service + // Delete the item in the database. + await GridProductService.Delete(deletedItem); - Console.WriteLine("Cancel event is fired."); + // Reload the data from the database. + GridData = await GridProductService.Read(); + // OR + // Delete the item in the local data too. + //GridData.Remove(deletedItem); } - // in a real case, keep the models in dedicated locations, this is just an easy to copy and see example - public class SampleData + private void OnGridEdit(GridCommandEventArgs args) { - public int ID { get; set; } - - [Required] - public string FirstName { get; set; } - - [Required] - public string MiddleName { get; set; } - - [Required] - public string LastName { get; set; } + if (ShouldCancelOnAddEdit) + { + args.IsCancelled = true; + return; + } } - public List MyData { get; set; } - - private async Task GetGridData() + private async Task OnGridUpdate(GridCommandEventArgs args) { - MyData = await MyService.Read(); + var updatedItem = (Product)args.Item; + + // Update the item in the database. + bool success = await GridProductService.Update(updatedItem); + + // Reload the data from the database. + GridData = await GridProductService.Read(); + // OR + // Update the item in the local data too. + //int originalItemIndex = GridData.FindIndex(i => i.Id == updatedItem.Id); + //if (originalItemIndex != -1) + //{ + // GridData[originalItemIndex] = updatedItem; + //} } protected override async Task OnInitializedAsync() { - await GetGridData(); + GridData = await GridProductService.Read(); } - // the following static class mimics an actual data service that handles the actual data source - // replace it with your actual service through the DI, this only mimics how the API can look like and works for this standalone page - public static class MyService + public class ProductService { - private static List _data { get; set; } = new List(); + private List Items { get; set; } - public static async Task Create(SampleData itemToInsert) + private int LastId { get; set; } + + public async Task Create(Product product) { - itemToInsert.ID = _data.Count + 1; - _data.Insert(0, itemToInsert); + // Simulate async operation. + await Task.Delay(100); + + product.Id = ++LastId; + + Items.Insert(0, product); + + return LastId; } - public static async Task> Read() + public async Task Delete(Product product) { - if (_data.Count < 1) + // Simulate async operation. + await Task.Delay(100); + + if (Items.Contains(product)) { - for (int i = 1; i < 50; i++) - { - _data.Add(new SampleData() - { - ID = i, - FirstName = "First " + i.ToString(), - MiddleName = "Middle " + i.ToString(), - LastName = "Last " + i.ToString(), - }); - } + Items.Remove(product); + + return true; } - return await Task.FromResult(_data); + return false; + } + + public async Task> Read() + { + // Simulate async operation. + await Task.Delay(100); + + return Items; + } + + public async Task Read(DataSourceRequest request) + { + return await Items.ToDataSourceResultAsync(request); } - public static async Task Update(SampleData itemToUpdate) + public async Task Update(Product product) { - var index = _data.FindIndex(i => i.ID == itemToUpdate.ID); - if (index != -1) + // Simulate async operation. + await Task.Delay(100); + + int originalItemIndex = Items.FindIndex(x => x.Id == product.Id); + + if (originalItemIndex != -1) { - _data[index] = itemToUpdate; + Items[originalItemIndex] = product; + return true; } + + return false; } - public static async Task Delete(SampleData itemToDelete) + public ProductService() { - _data.Remove(itemToDelete); + Items = new(); + + for (int i = 1; i <= 15; i++) + { + Items.Add(new Product() + { + Id = ++LastId, + Name = $"Product {LastId}", + Description = $"Multi-line\ndescription {LastId}", + Price = LastId % 2 == 0 ? null : Random.Shared.Next(0, 100) * 1.23m, + Quantity = LastId % 2 == 0 ? 0 : Random.Shared.Next(0, 3000), + ReleaseDate = DateTime.Today.AddDays(-Random.Shared.Next(365, 3650)), + Discontinued = LastId % 2 == 0 + }); + } + } } + + public class Product + { + public int Id { get; set; } + [Required] + public string Name { get; set; } = string.Empty; + public string Description { get; set; } = string.Empty; + public decimal? Price { get; set; } + public int Quantity { get; set; } + [Required] + public DateTime? ReleaseDate { get; set; } + public bool Discontinued { get; set; } + } } ```` From 987284d79267500e3426cde0095339e17ba82efd Mon Sep 17 00:00:00 2001 From: Dimo Dimov <961014+dimodi@users.noreply.github.com> Date: Tue, 11 Feb 2025 16:31:02 +0200 Subject: [PATCH 02/33] continued --- components/grid/editing/incell.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/components/grid/editing/incell.md b/components/grid/editing/incell.md index 0db71d60b..7b946b914 100644 --- a/components/grid/editing/incell.md +++ b/components/grid/editing/incell.md @@ -332,6 +332,19 @@ The incell editor template requires a focusable element to maintain the tab orde ```` +## Examples + +The following two examples show Grid in-cell editing in action: + +* A basic example that includes only the minimum required setup. +* A more comprehensive example that includes additional event handlers, custom logic, and a simulated data service. + + +### Basic InCell Editing Example + +### Comprehensive InCell Editing Example + + ## See Also * [Live Demo: Grid InCell Editing](https://demos.telerik.com/blazor-ui/grid/editing-incell) From 84a8603d68bcb01ce94e74849971fc010e4757ee Mon Sep 17 00:00:00 2001 From: Dimo Dimov <961014+dimodi@users.noreply.github.com> Date: Sat, 15 Feb 2025 10:15:53 +0200 Subject: [PATCH 03/33] Revamp continued --- components/grid/editing/overview.md | 412 ++++----------------- knowledge-base/grid-checkbox-editing.md | 1 + knowledge-base/grid-edit-all-rows-cells.md | 196 ++++++++++ 3 files changed, 268 insertions(+), 341 deletions(-) create mode 100644 knowledge-base/grid-edit-all-rows-cells.md diff --git a/components/grid/editing/overview.md b/components/grid/editing/overview.md index f89360847..632ac6d05 100644 --- a/components/grid/editing/overview.md +++ b/components/grid/editing/overview.md @@ -3,33 +3,72 @@ title: Overview page_title: Grid - CRUD Overview description: CRUD basics for the Grid for Blazor. slug: components/grid/editing/overview -tags: telerik,blazor,grid,editing,overview +tags: telerik, blazor, grid, editing published: True position: 0 --- # Blazor Grid CRUD Operations -The Blazor Grid supports CRUD operations and validation. Use the CRUD events to transfer the changes to the underlying data source (for example, call a service to update the database, and not only with the view data). +The Telerik Grid for Blazor supports create, update, and delete operations (CRUD). The component can also validate the user input. Use the CRUD events to transfer the changes to the underlying data source (for example, call a service to update the database, and not only with the view data). -This page explains how to enable editing, use the relevant events and command buttons. There is also a runnable code example. +This page explains how to: -#### In this article: +* Enable editing +* Use the relevant events +* Define command buttons -- [Basics](#basics) -- [Events](#events) -- [Customize The Editor Fields](#customize-the-editor-fields) -- [Example](#example) -- [Notes](#notes) +## Edit Modes -## Basics +The Grid offers several editing modes with different user experience. To allow users to add or edit data items in the GRid: -The Grid offers several editing modes with different user experience. Set the `EditMode` property to a member of the `GridEditMode` enum: +1. Set the `EditMode` parameter to a [member of the `GridEditMode` enum](slug:telerik.blazor.grideditmode). +1. Define the required [events](#events) and appropriate [command buttons](#commands) for the selected edit mode and operations. -* `None` - the default `GridEditMode` value. The built-in [`Add` and `Edit` commands](slug:components/grid/columns/command#built-in-commands) don't work in this mode. -* `Incell` - [edit a single cell](slug:components/grid/editing/incell) by clicking on it or tabbing -* `Inline` - [edit a row](slug:components/grid/editing/inline) by clicking on an [Edit command button](slug:components/grid/columns/command) -* `Popup` - [edit a row in a popup form](slug:components/grid/editing/popup) by clicking on an Edit button +The default Grid edit mode is `GridEditMode.None`. The built-in [`Add` and `Edit` commands](slug://components/grid/columns/command#built-in-commands) don't work in this mode. + +All Grid edit modes work with one cell or one row. Editing multiple rows at the same time is not supported. You can [render editors in all Grid data cells through column `