diff --git a/components/grid/columns/auto-generated.md b/components/grid/columns/auto-generated.md
index 3f4be1449e..5231922f1f 100644
--- a/components/grid/columns/auto-generated.md
+++ b/components/grid/columns/auto-generated.md
@@ -199,33 +199,30 @@ This example shows how to:
@using System.Collections.ObjectModel
-
-
-
-
-
- Add
-
-
-
-
-
-
- Edit
- Delete
-
-
-
-
+
+
+
+ Add
+
+
+
+
+
+
+ Edit
+ Delete
+
+
+
@if (SelectedUsers.Any())
@@ -253,7 +250,6 @@ This example shows how to:
public List GridData { get; set; }
public IEnumerable SelectedUsers { get; set; } = new ObservableCollection();
public int PageSize { get; set; } = 3;
- GridDataModel DataModel = new GridDataModel();
#region data model with annotations
public class GridDataModel
@@ -290,14 +286,10 @@ This example shows how to:
GridDataModel item = (GridDataModel)args.Item;
// perform actual data source operations here through your service
- GridDataModel updatedItem = await ServiceMimicUpdate(item);
+ await MyService.Update(item);
- // update the local view-model data
- var index = GridData.FindIndex(i => i.Id == updatedItem.Id);
- if (index != -1)
- {
- GridData[index] = updatedItem;
- }
+ // update the local view-model data with the service data
+ await GetGridData();
}
async Task DeleteItem(GridCommandEventArgs args)
@@ -305,13 +297,10 @@ This example shows how to:
GridDataModel item = (GridDataModel)args.Item;
// perform actual data source operation here through your service
- bool isDeleted = await ServiceMimicDelete(item);
+ await MyService.Delete(item);
- if (isDeleted)
- {
- // update the local view-model data
- GridData.Remove(item);
- }
+ // update the local view-model data with the service data
+ await GetGridData();
}
async Task CreateItem(GridCommandEventArgs args)
@@ -319,77 +308,70 @@ This example shows how to:
GridDataModel item = (GridDataModel)args.Item;
// perform actual data source operation here through your service
- GridDataModel insertedItem = await ServiceMimicInsert(item);
+ await MyService.Create(item);
- // update the local view-model data
- GridData.Insert(0, insertedItem);
+ // update the local view-model data with the service data
+ await GetGridData();
}
+ #endregion
- // the following three methods mimic an actual data service that handles the actual data source
- // you can see about implement error and exception handling, determining suitable return types as per your needs
- // an example is available here: https://github.com/telerik/blazor-ui/tree/master/grid/remote-validation
-
- async Task ServiceMimicInsert(GridDataModel itemToInsert)
+ async Task GetGridData()
{
- // in this example, we just populate the fields, you project may use
- // something else or generate the updated item differently
- GridDataModel updatedItem = new GridDataModel()
- {
- // the service assigns an ID, in this sample we use only the view-model data for simplicity,
- // you should use the actual data and set the properties as necessary (e.g., generate nested fields data and so on)
- Id = GridData.Count + 1,
- Username = itemToInsert.Username,
- EmailAddress = itemToInsert.EmailAddress,
- RegistrationDate = itemToInsert.RegistrationDate,
- LocalTime = itemToInsert.LocalTime,
- BoughtBooks = itemToInsert.BoughtBooks
- };
- return await Task.FromResult(updatedItem);
+ GridData = await MyService.Read();
}
- async Task ServiceMimicUpdate(GridDataModel itemToUpdate)
+ protected override async Task OnInitializedAsync()
{
- // in this example, we just populate the fields, you project may use
- // something else or generate the updated item differently
- GridDataModel updatedItem = new GridDataModel()
- {
- Id = itemToUpdate.Id,
- Username = itemToUpdate.Username,
- EmailAddress = itemToUpdate.EmailAddress,
- RegistrationDate = itemToUpdate.RegistrationDate,
- LocalTime = itemToUpdate.LocalTime,
- BoughtBooks = itemToUpdate.BoughtBooks
- };
- return await Task.FromResult(updatedItem);
+ await GetGridData();
}
- async Task ServiceMimicDelete(GridDataModel itemToDelete)
+ // 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
{
- return await Task.FromResult(true);//always successful
- }
+ private static List _data { get; set; } = new List();
- #endregion
+ public static async Task Create(GridDataModel itemToInsert)
+ {
+ itemToInsert.Id = _data.Count + 1;
+ _data.Insert(0, itemToInsert);
+ }
- #region data generation
- protected override void OnInitialized()
- {
- GridData = new List();
- for (int i = 0; i < 45; i++)
+ public static async Task> Read()
+ {
+ if (_data.Count < 1)
+ {
+ for (int i = 0; i < 45; i++)
+ {
+ _data.Add(new GridDataModel()
+ {
+ Id = i,
+ Username = $"Username {i}",
+ EmailAddress = $"user{i}@mail.com",
+ RegistrationDate = DateTime.Now.AddDays(-2),
+ LocalTime = DateTime.Now
+ });
+ }
+ }
+
+ return await Task.FromResult(_data);
+ }
+
+ public static async Task Update(GridDataModel itemToUpdate)
{
- GridData.Add(new GridDataModel()
+ var index = _data.FindIndex(i => i.Id == itemToUpdate.Id);
+ if (index != -1)
{
- Id = i,
- Username = $"Username {i}",
- EmailAddress = $"user{i}@mail.com",
- RegistrationDate = DateTime.Now.AddDays(-2),
- LocalTime = DateTime.Now
- });
+ _data[index] = itemToUpdate;
+ }
}
- base.OnInitialized();
+ public static async Task Delete(GridDataModel itemToDelete)
+ {
+ _data.Remove(itemToDelete);
+ }
}
- #endregion
}
````
>caption The result from the code snippet above
diff --git a/components/grid/columns/command.md b/components/grid/columns/command.md
index f1504318ae..77540934b8 100644
--- a/components/grid/columns/command.md
+++ b/components/grid/columns/command.md
@@ -99,12 +99,7 @@ The following code example demonstrates declarations and handling.
public DateTime HireDate { get; set; }
}
- List GridData = Enumerable.Range(1, 50).Select(x => new SampleData
- {
- ID = x,
- Name = "name " + x,
- HireDate = DateTime.Now.AddDays(-x)
- }).ToList();
+ List GridData { get; set; }
// sample custom commands handling
@@ -129,36 +124,61 @@ The following code example demonstrates declarations and handling.
}
- // sample CUD operations
+ // sample CRUD operations
private async Task MyUpdateHandler(GridCommandEventArgs args)
{
SampleData theUpdatedItem = args.Item as SampleData;
- SampleData updatedItem = await ServiceMimicUpdate(theUpdatedItem);
- // update the local view-model data
- var index = GridData.FindIndex(i => i.ID == updatedItem.ID);
- if (index != -1)
- {
- GridData[index] = updatedItem;
- }
+ // perform actual data source operations here through your service
+ await MyService.Update(theUpdatedItem);
+
+ // update the local view-model data with the service data
+ await GetGridData();
+ }
+
+ async Task GetGridData()
+ {
+ GridData = await MyService.Read();
}
- // the following method mimics an actual data service that handles the actual data source
- // you can see about implement error and exception handling, determining suitable return types as per your needs
- // an example is available here: https://github.com/telerik/blazor-ui/tree/master/grid/remote-validation
+ protected override async Task OnInitializedAsync()
+ {
+ await GetGridData();
+ }
- async Task ServiceMimicUpdate(SampleData itemToUpdate)
+ // 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
{
- // in this example, we just populate the fields, you project may use
- // something else or generate the updated item differently
- SampleData updatedItem = new SampleData()
+ private static List _data { get; set; } = new List();
+
+ public static async Task> Read()
{
- ID = itemToUpdate.ID,
- HireDate = itemToUpdate.HireDate,
- Name = itemToUpdate.Name
- };
- return await Task.FromResult(updatedItem);
+ if (_data.Count < 1)
+ {
+ for (int i = 1; i < 50; i++)
+ {
+ _data.Add(new SampleData()
+ {
+ ID = i,
+ Name = "name " + i,
+ HireDate = DateTime.Now.AddDays(-i)
+ });
+ }
+ }
+
+ return await Task.FromResult(_data);
+ }
+
+ public static async Task Update(SampleData itemToUpdate)
+ {
+ var index = _data.FindIndex(i => i.ID == itemToUpdate.ID);
+ if (index != -1)
+ {
+ _data[index] = itemToUpdate;
+ }
+ }
}
}
````
diff --git a/components/grid/editing/incell.md b/components/grid/editing/incell.md
index b40f5a1185..7e5bbc8cc8 100644
--- a/components/grid/editing/incell.md
+++ b/components/grid/editing/incell.md
@@ -66,14 +66,10 @@ Click a cell, edit it and click outside of the cell to see the change.
SampleData item = (SampleData)args.Item;
// perform actual data source operations here through your service
- SampleData updatedItem = await ServiceMimicUpdate(item);
+ await MyService.Update(item);
- // update the local view-model data
- var index = MyData.FindIndex(i => i.ID == updatedItem.ID);
- if (index != -1)
- {
- MyData[index] = updatedItem;
- }
+ // update the local view-model data with the service data
+ await GetGridData();
Console.WriteLine("Update event is fired.");
}
@@ -83,13 +79,10 @@ Click a cell, edit it and click outside of the cell to see the change.
SampleData item = (SampleData)args.Item;
// perform actual data source operation here through your service
- bool isDeleted = await ServiceMimicDelete(item);
+ await MyService.Delete(item);
- if (isDeleted)
- {
- // update the local view-model data
- MyData.Remove(item);
- }
+ // update the local view-model data with the service data
+ await GetGridData();
Console.WriteLine("Delete event is fired.");
}
@@ -99,71 +92,75 @@ Click a cell, edit it and click outside of the cell to see the change.
SampleData item = (SampleData)args.Item;
// perform actual data source operation here through your service
- SampleData insertedItem = await ServiceMimicInsert(item);
+ await MyService.Create(item);
- // update the local view-model data
- MyData.Insert(0, insertedItem);
+ // update the local view-model data with the service data
+ await GetGridData();
Console.WriteLine("Create event is fired.");
}
- // the following three methods mimic an actual data service that handles the actual data source
- // you can see about implement error and exception handling, determining suitable return types as per your needs
- // an example is available here: https://github.com/telerik/blazor-ui/tree/master/grid/remote-validation
-
- async Task ServiceMimicInsert(SampleData itemToInsert)
+ // in a real case, keep the models in dedicated locations, this is just an easy to copy and see example
+ public class SampleData
{
- // in this example, we just populate the fields, you project may use
- // something else or generate the updated item differently
- SampleData updatedItem = new SampleData()
- {
- // the service assigns an ID, in this sample we use only the view-model data for simplicity,
- // you should use the actual data and set the properties as necessary (e.g., generate nested fields data and so on)
- ID = MyData.Count + 1,
- Name = itemToInsert.Name
- };
- return await Task.FromResult(updatedItem);
+ public int ID { get; set; }
+ public string Name { get; set; }
}
- async Task ServiceMimicUpdate(SampleData itemToUpdate)
+ public List MyData { get; set; }
+
+ async Task GetGridData()
{
- // in this example, we just populate the fields, you project may use
- // something else or generate the updated item differently
- SampleData updatedItem = new SampleData()
- {
- ID = itemToUpdate.ID,
- Name = itemToUpdate.Name
- };
- return await Task.FromResult(updatedItem);
+ MyData = await MyService.Read();
}
- async Task ServiceMimicDelete(SampleData itemToDelete)
+ protected override async Task OnInitializedAsync()
{
- return await Task.FromResult(true);//always successful
+ await GetGridData();
}
-
- // in a real case, keep the models in dedicated locations, this is just an easy to copy and see example
- public class SampleData
+ // 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 int ID { get; set; }
- public string Name { get; set; }
- }
+ private static List _data { get; set; } = new List();
- public List MyData { get; set; }
+ public static async Task Create(SampleData itemToInsert)
+ {
+ itemToInsert.Id = _data.Count + 1;
+ _data.Insert(0, itemToInsert);
+ }
- protected override void OnInitialized()
- {
- MyData = new List();
+ public static async Task> Read()
+ {
+ if (_data.Count < 1)
+ {
+ for (int i = 1; i < 50; i++)
+ {
+ _data.Add(new SampleData()
+ {
+ ID = i,
+ Name = "Name " + i.ToString()
+ });
+ }
+ }
+
+ return await Task.FromResult(_data);
+ }
- for (int i = 1; i < 50; i++)
+ public static async Task Update(SampleData itemToUpdate)
{
- MyData.Add(new SampleData()
+ var index = _data.FindIndex(i => i.ID == itemToUpdate.ID);
+ if (index != -1)
{
- ID = i,
- Name = "Name " + i.ToString()
- });
+ _data[index] = itemToUpdate;
+ }
+ }
+
+ public static async Task Delete(SampleData itemToDelete)
+ {
+ _data.Remove(itemToDelete);
}
}
}
diff --git a/components/grid/editing/inline.md b/components/grid/editing/inline.md
index 1e92589bd0..a1d46244a1 100644
--- a/components/grid/editing/inline.md
+++ b/components/grid/editing/inline.md
@@ -62,14 +62,10 @@ Use the command buttons to control the CUD operations.
SampleData item = (SampleData)args.Item;
// perform actual data source operations here through your service
- SampleData updatedItem = await ServiceMimicUpdate(item);
+ await MyService.Update(item);
- // update the local view-model data
- var index = MyData.FindIndex(i => i.ID == updatedItem.ID);
- if (index != -1)
- {
- MyData[index] = updatedItem;
- }
+ // update the local view-model data with the service data
+ await GetGridData();
Console.WriteLine("Update event is fired.");
}
@@ -79,13 +75,10 @@ Use the command buttons to control the CUD operations.
SampleData item = (SampleData)args.Item;
// perform actual data source operation here through your service
- bool isDeleted = await ServiceMimicDelete(item);
+ await MyService.Delete(item);
- if (isDeleted)
- {
- // update the local view-model data
- MyData.Remove(item);
- }
+ // update the local view-model data with the service data
+ await GetGridData();
Console.WriteLine("Delete event is fired.");
}
@@ -95,10 +88,10 @@ Use the command buttons to control the CUD operations.
SampleData item = (SampleData)args.Item;
// perform actual data source operation here through your service
- SampleData insertedItem = await ServiceMimicInsert(item);
+ await MyService.Create(item);
- // update the local view-model data
- MyData.Insert(0, insertedItem);
+ // update the local view-model data with the service data
+ await GetGridData();
Console.WriteLine("Create event is fired.");
}
@@ -112,62 +105,67 @@ Use the command buttons to control the CUD operations.
Console.WriteLine("Cancel event is fired.");
}
- // the following three methods mimic an actual data service that handles the actual data source
- // you can see about implement error and exception handling, determining suitable return types as per your needs
- // an example is available here: https://github.com/telerik/blazor-ui/tree/master/grid/remote-validation
- async Task ServiceMimicInsert(SampleData itemToInsert)
+ // in a real case, keep the models in dedicated locations, this is just an easy to copy and see example
+ public class SampleData
{
- // in this example, we just populate the fields, you project may use
- // something else or generate the inserted item differently
- SampleData updatedItem = new SampleData()
- {
- // the service assigns an ID, in this sample we use only the view-model data for simplicity,
- // you should use the actual data and set the properties as necessary (e.g., generate nested fields data and so on)
- ID = MyData.Count + 1,
- Name = itemToInsert.Name
- };
- return await Task.FromResult(updatedItem);
+ public int ID { get; set; }
+ public string Name { get; set; }
}
- async Task ServiceMimicUpdate(SampleData itemToUpdate)
+ public List MyData { get; set; }
+
+ async Task GetGridData()
{
- // in this example, we just populate the fields, you project may use
- // something else or generate the updated item differently
- SampleData updatedItem = new SampleData()
- {
- ID = itemToUpdate.ID,
- Name = itemToUpdate.Name
- };
- return await Task.FromResult(updatedItem);
+ MyData = await MyService.Read();
}
- async Task ServiceMimicDelete(SampleData itemToDelete)
+ protected override async Task OnInitializedAsync()
{
- return await Task.FromResult(true);//always successful
+ await GetGridData();
}
-
- // in a real case, keep the models in dedicated locations, this is just an easy to copy and see example
- public class SampleData
+ // 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 int ID { get; set; }
- public string Name { get; set; }
- }
+ private static List _data { get; set; } = new List();
- public List MyData { get; set; }
+ public static async Task Create(SampleData itemToInsert)
+ {
+ itemToInsert.Id = _data.Count + 1;
+ _data.Insert(0, itemToInsert);
+ }
- protected override void OnInitialized()
- {
- MyData = new List();
+ public static async Task> Read()
+ {
+ if (_data.Count < 1)
+ {
+ for (int i = 1; i < 50; i++)
+ {
+ _data.Add(new SampleData()
+ {
+ ID = i,
+ Name = "Name " + i.ToString()
+ });
+ }
+ }
+
+ return await Task.FromResult(_data);
+ }
- for (int i = 1; i < 50; i++)
+ public static async Task Update(SampleData itemToUpdate)
{
- MyData.Add(new SampleData()
+ var index = _data.FindIndex(i => i.ID == itemToUpdate.ID);
+ if (index != -1)
{
- ID = i,
- Name = "Name " + i.ToString()
- });
+ _data[index] = itemToUpdate;
+ }
+ }
+
+ public static async Task Delete(SampleData itemToDelete)
+ {
+ _data.Remove(itemToDelete);
}
}
}
diff --git a/components/grid/editing/overview.md b/components/grid/editing/overview.md
index c675bacd41..f051bc8dda 100644
--- a/components/grid/editing/overview.md
+++ b/components/grid/editing/overview.md
@@ -74,8 +74,6 @@ Editing is cancelled for the first two records.
@code {
async Task EditHandler(GridCommandEventArgs args)
{
- AppendToLog("Edit", args);
-
SampleData item = (SampleData)args.Item;
//prevent opening for edit based on condition
@@ -83,6 +81,8 @@ Editing is cancelled for the first two records.
{
args.IsCancelled = true;//the general approach for cancelling an event
}
+
+ AppendToLog("Edit", args);
}
async Task UpdateHandler(GridCommandEventArgs args)
@@ -92,14 +92,10 @@ Editing is cancelled for the first two records.
SampleData item = (SampleData)args.Item;
// perform actual data source operations here through your service
- SampleData updatedItem = await ServiceMimicUpdate(item);
-
+ await MyService.Update(item);
+
// update the local view-model data with the service data
- var index = MyData.FindIndex(i => i.ID == updatedItem.ID);
- if (index != -1)
- {
- MyData[index] = updatedItem;
- }
+ await GetGridData();
}
async Task DeleteHandler(GridCommandEventArgs args)
@@ -109,13 +105,11 @@ Editing is cancelled for the first two records.
SampleData item = (SampleData)args.Item;
// perform actual data source operation here through your service
- bool isDeleted = await ServiceMimicDelete(item);
-
- if (isDeleted)
- {
- // update the local view-model data
- MyData.Remove(item);
- }
+ await MyService.Delete(item);
+
+ // update the local view-model data with the service data
+ await GetGridData();
+
}
async Task CreateHandler(GridCommandEventArgs args)
@@ -125,10 +119,10 @@ Editing is cancelled for the first two records.
SampleData item = (SampleData)args.Item;
// perform actual data source operation here through your service
- SampleData insertedItem = await ServiceMimicInsert(item);
-
+ await MyService.Create(item);
+
// update the local view-model data with the service data
- MyData.Insert(0, insertedItem);
+ await GetGridData();
}
async Task CancelHandler(GridCommandEventArgs args)
@@ -142,44 +136,6 @@ Editing is cancelled for the first two records.
await Task.Delay(1000); //simulate actual long running async operation
}
- // the following three methods mimic an actual data service that handles the actual data source
- // you can see about implement error and exception handling, determining suitable return types as per your needs
- // an example is available here: https://github.com/telerik/blazor-ui/tree/master/grid/remote-validation
-
- async Task ServiceMimicInsert(SampleData itemToInsert)
- {
- await Task.Delay(2000); // simulate actual long running async operation
- // in this example, we just populate the fields, you project may use
- // something else or generate the updated item differently, we use "new" here
- SampleData updatedItem = new SampleData()
- {
- // the service assigns an ID, in this sample we use only the view-model data for simplicity,
- // you should use the actual data and set the properties as necessary (e.g., generate nested fields data and so on)
- ID = MyData.Count + 1,
- Name = itemToInsert.Name
- };
- return await Task.FromResult(updatedItem);
- }
-
- async Task ServiceMimicUpdate(SampleData itemToUpdate)
- {
- await Task.Delay(2000); // simulate actual long running async operation
- // in this example, we just populate the fields, you project may use
- // something else or generate the updated item differently
- SampleData updatedItem = new SampleData()
- {
- ID = itemToUpdate.ID,
- Name = itemToUpdate.Name
- };
- return await Task.FromResult(updatedItem);
- }
-
- async Task ServiceMimicDelete(SampleData itemToDelete)
- {
- await Task.Delay(2000); // simulate actual long running async operation
- return await Task.FromResult(true);//always successful
- }
-
// this method and field just display what happened for visual cues in this example
MarkupString logger;
@@ -204,17 +160,66 @@ Editing is cancelled for the first two records.
List MyData { get; set; }
- protected override void OnInitialized()
+ async Task GetGridData()
+ {
+ MyData = await MyService.Read();
+ }
+
+ protected override async Task OnInitializedAsync()
+ {
+ await GetGridData();
+ }
+
+
+ // 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 will look like and works for this standalone page
+ public static class MyService
{
- MyData = new List();
+ private static List _data { get; set; } = new List();
+
+ public static async Task Create(SampleData itemToInsert)
+ {
+ await Task.Delay(1000); // simulate actual long running async operation
+
+ itemToInsert.Id = _data.Count + 1;
+ _data.Insert(0, itemToInsert);
+ }
- for (int i = 0; i < 50; i++)
+ public static async Task> Read()
{
- MyData.Add(new SampleData()
+ await Task.Delay(1000); // simulate actual long running async operation
+
+ if (_data.Count < 1)
+ {
+ for (int i = 1; i < 50; i++)
+ {
+ _data.Add(new SampleData()
+ {
+ ID = i,
+ Name = "Name " + i.ToString()
+ });
+ }
+ }
+
+ return await Task.FromResult(_data);
+ }
+
+ public static async Task Update(SampleData itemToUpdate)
+ {
+ await Task.Delay(1000); // simulate actual long running async operation
+
+ var index = _data.FindIndex(i => i.ID == itemToUpdate.ID);
+ if (index != -1)
{
- ID = i,
- Name = "Name " + i.ToString()
- });
+ _data[index] = itemToUpdate;
+ }
+ }
+
+ public static async Task Delete(SampleData itemToDelete)
+ {
+ await Task.Delay(1000); // simulate actual long running async operation
+
+ _data.Remove(itemToDelete);
}
}
}
@@ -230,7 +235,9 @@ There are a few considerations to keep in mind with the CUD operations of the gr
* For example, you may want to update the view-model only on success of the data service with the model returned from the server. Another thing you may want to do is to inform the user for server (async, remote) validation errors such as duplicates. You can find examples of both in the [Remote Validation sample project](https://github.com/telerik/blazor-ui/tree/master/grid/remote-validation).
-* The CRUD event handlers must be `async Task` and **not** `async void`. A Task can be properly awaited and allows working with services and contexts. When the method returns `void`, the execution of the context operations is not actually awaited, and you may get errors from the context (such as "Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application" or "A second operation started on this context before a previous operation completed. This is usually caused by different threads using the same instance of DbContext").
+* The CRUD event handlers must be `async Task` and **not** `async void`. A Task can be properly awaited and allows working with services and contexts, and lets the grid update after the actual data source operations complete.
+
+ * When the method returns `void`, the execution of the context operations is not actually awaited, and you may get errors from the context (such as "Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application" or "A second operation started on this context before a previous operation completed. This is usually caused by different threads using the same instance of DbContext"). The grid may also re-render before the actual data update happens and you may not see the result.
* The Grid uses `Activator.CreateInstance();` to generate a new item when an Insert action is invoked, so the Model should have a Parameterless constructor defined. A workaround might be [invoking Insert through the grid state]({%slug grid-state%}#initiate-editing-or-inserting-of-an-item) and creating the object with your own code.
diff --git a/components/grid/editing/popup.md b/components/grid/editing/popup.md
index c06ffcc1cb..3a7a068eeb 100644
--- a/components/grid/editing/popup.md
+++ b/components/grid/editing/popup.md
@@ -65,14 +65,10 @@ The PopUp editing mode supports [validation]({%slug common-features/input-valida
SampleData item = (SampleData)args.Item;
// perform actual data source operations here through your service
- SampleData updatedItem = await ServiceMimicUpdate(item);
+ await MyService.Update(item);
- // update the local view-model data
- var index = MyData.FindIndex(i => i.ID == updatedItem.ID);
- if (index != -1)
- {
- MyData[index] = updatedItem;
- }
+ // update the local view-model data with the service data
+ await GetGridData();
Console.WriteLine("Update event is fired.");
}
@@ -82,13 +78,10 @@ The PopUp editing mode supports [validation]({%slug common-features/input-valida
SampleData item = (SampleData)args.Item;
// perform actual data source operation here through your service
- bool isDeleted = await ServiceMimicDelete(item);
+ await MyService.Delete(item);
- if (isDeleted)
- {
- // update the local view-model data
- MyData.Remove(item);
- }
+ // update the local view-model data with the service data
+ await GetGridData();
Console.WriteLine("Delete event is fired.");
}
@@ -98,10 +91,10 @@ The PopUp editing mode supports [validation]({%slug common-features/input-valida
SampleData item = (SampleData)args.Item;
// perform actual data source operation here through your service
- SampleData insertedItem = await ServiceMimicInsert(item);
+ await MyService.Create(item);
- // update the local view-model data
- MyData.Insert(0, insertedItem);
+ // update the local view-model data with the service data
+ await GetGridData();
Console.WriteLine("Create event is fired.");
}
@@ -115,42 +108,6 @@ The PopUp editing mode supports [validation]({%slug common-features/input-valida
Console.WriteLine("Cancel event is fired.");
}
- // the following three methods mimic an actual data service that handles the actual data source
- // you can see about implement error and exception handling, determining suitable return types as per your needs
- // an example is available here: https://github.com/telerik/blazor-ui/tree/master/grid/remote-validation
-
- async Task ServiceMimicInsert(SampleData itemToInsert)
- {
- // in this example, we just populate the fields, you project may use
- // something else or generate the inserted item differently
- SampleData updatedItem = new SampleData()
- {
- // the service assigns an ID, in this sample we use only the view-model data for simplicity,
- // you should use the actual data and set the properties as necessary (e.g., generate nested fields data and so on)
- ID = MyData.Count + 1,
- Name = itemToInsert.Name
- };
- return await Task.FromResult(updatedItem);
- }
-
- async Task ServiceMimicUpdate(SampleData itemToUpdate)
- {
- // in this example, we just populate the fields, you project may use
- // something else or generate the updated item differently
- SampleData updatedItem = new SampleData()
- {
- ID = itemToUpdate.ID,
- Name = itemToUpdate.Name
- };
- return await Task.FromResult(updatedItem);
- }
-
- async Task ServiceMimicDelete(SampleData itemToDelete)
- {
- return await Task.FromResult(true);//always successful
- }
-
-
// in a real case, keep the models in dedicated locations, this is just an easy to copy and see example
public class SampleData
{
@@ -162,17 +119,57 @@ The PopUp editing mode supports [validation]({%slug common-features/input-valida
public List MyData { get; set; }
- protected override void OnInitialized()
+ async Task GetGridData()
{
- MyData = new List();
+ MyData = await MyService.Read();
+ }
+
+ protected override async Task OnInitializedAsync()
+ {
+ await GetGridData();
+ }
+
+ // 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
+ {
+ private static List _data { get; set; } = new List();
+
+ public static async Task Create(SampleData itemToInsert)
+ {
+ itemToInsert.Id = _data.Count + 1;
+ _data.Insert(0, itemToInsert);
+ }
+
+ public static async Task> Read()
+ {
+ if (_data.Count < 1)
+ {
+ for (int i = 1; i < 50; i++)
+ {
+ _data.Add(new SampleData()
+ {
+ ID = i,
+ Name = "Name " + i.ToString()
+ });
+ }
+ }
+
+ return await Task.FromResult(_data);
+ }
- for (int i = 1; i < 50; i++)
+ public static async Task Update(SampleData itemToUpdate)
{
- MyData.Add(new SampleData()
+ var index = _data.FindIndex(i => i.ID == itemToUpdate.ID);
+ if (index != -1)
{
- ID = i,
- Name = "Name " + i.ToString()
- });
+ _data[index] = itemToUpdate;
+ }
+ }
+
+ public static async Task Delete(SampleData itemToDelete)
+ {
+ _data.Remove(itemToDelete);
}
}
}
diff --git a/components/grid/images/create-toolbar-button.jpg b/components/grid/images/create-toolbar-button.jpg
deleted file mode 100644
index 7f841cd08a..0000000000
Binary files a/components/grid/images/create-toolbar-button.jpg and /dev/null differ
diff --git a/components/grid/images/create-toolbar-button.png b/components/grid/images/create-toolbar-button.png
new file mode 100644
index 0000000000..daac6d6503
Binary files /dev/null and b/components/grid/images/create-toolbar-button.png differ
diff --git a/components/grid/state.md b/components/grid/state.md
index d33937b072..2f98e5f411 100644
--- a/components/grid/state.md
+++ b/components/grid/state.md
@@ -119,7 +119,6 @@ The following example shows one way you can store the grid state - through a cus
````Component
@inject LocalStorage LocalStorage
@inject IJSRuntime JsInterop
-
Change something in the grid (like sort, filter, select, page, resize columns, etc.), then reload the page to see the grid state fetched from the browser local storage.
@@ -169,6 +168,9 @@ Change something in the grid (like sort, filter, select, page, resize columns, e
// Load and Save the state through the grid events
string UniqueStorageKey = "SampleGridStateStorageThatShouldBeUnique";
+ TelerikGrid Grid { get; set; }
+ IEnumerable SelectedItems { get; set; } = Enumerable.Empty();
+ List GridData { get; set; }
async Task OnStateInitHandler(GridStateEventArgs args)
{
@@ -193,7 +195,6 @@ Change something in the grid (like sort, filter, select, page, resize columns, e
await LocalStorage.SetItem(UniqueStorageKey, args.GridState);
}
- TelerikGrid Grid { get; set; }
async Task ResetState()
{
// clean up the storage
@@ -214,14 +215,12 @@ Change something in the grid (like sort, filter, select, page, resize columns, e
SampleData item = (SampleData)args.Item;
// perform actual data source operations here through your service
- SampleData updatedItem = await ServiceMimicUpdate(item);
+ await MyService.Update(item);
- // update the local view-model data
- var index = GridData.FindIndex(i => i.Id == updatedItem.Id);
- if (index != -1)
- {
- GridData[index] = updatedItem;
- }
+ // update the local view-model data with the service data
+ await GetGridData();
+
+ Console.WriteLine("Update event is fired.");
}
async Task DeleteItem(GridCommandEventArgs args)
@@ -229,13 +228,12 @@ Change something in the grid (like sort, filter, select, page, resize columns, e
SampleData item = (SampleData)args.Item;
// perform actual data source operation here through your service
- bool isDeleted = await ServiceMimicDelete(item);
+ await MyService.Delete(item);
- if (isDeleted)
- {
- // update the local view-model data
- GridData.Remove(item);
- }
+ // update the local view-model data with the service data
+ await GetGridData();
+
+ Console.WriteLine("Delete event is fired.");
}
async Task CreateItem(GridCommandEventArgs args)
@@ -243,79 +241,89 @@ Change something in the grid (like sort, filter, select, page, resize columns, e
SampleData item = (SampleData)args.Item;
// perform actual data source operation here through your service
- SampleData insertedItem = await ServiceMimicInsert(item);
+ await MyService.Create(item);
- // update the local view-model data
- GridData.Insert(0, insertedItem);
- }
+ // update the local view-model data with the service data
+ await GetGridData();
+ Console.WriteLine("Create event is fired.");
+ }
- // the following three methods mimic an actual data service that handles the actual data source
- // you can see about implement error and exception handling, determining suitable return types as per your needs
- // an example is available here: https://github.com/telerik/blazor-ui/tree/master/grid/remote-validation
+ // Note the Equals override for restoring selection and editing
- async Task ServiceMimicInsert(SampleData itemToInsert)
+ public class SampleData
{
- // in this example, we just populate the fields, you project may use
- // something else or generate the updated item differently
- SampleData updatedItem = new SampleData()
+ public int Id { get; set; }
+ public string Name { get; set; }
+ public string Team { get; set; }
+
+ // example of comparing stored items (from editing or selection)
+ // with items from the current data source - IDs are used instead of the default references
+ public override bool Equals(object obj)
{
- // the service assigns an ID, in this sample we use only the view-model data for simplicity,
- // you should use the actual data and set the properties as necessary (e.g., generate nested fields data and so on)
- Id = GridData.Count + 1,
- Name = itemToInsert.Name,
- Team = itemToInsert.Team
- };
- return await Task.FromResult(updatedItem);
+ if (obj is SampleData)
+ {
+ return this.Id == (obj as SampleData).Id;
+ }
+ return false;
+ }
}
- async Task ServiceMimicUpdate(SampleData itemToUpdate)
+ async Task GetGridData()
{
- // in this example, we just populate the fields, you project may use
- // something else or generate the updated item differently
- SampleData updatedItem = new SampleData()
- {
- Id = itemToUpdate.Id,
- Name = itemToUpdate.Name,
- Team = itemToUpdate.Team
- };
- return await Task.FromResult(updatedItem);
+ GridData = await MyService.Read();
}
- async Task ServiceMimicDelete(SampleData itemToDelete)
+ protected override async Task OnInitializedAsync()
{
- return await Task.FromResult(true);//always successful
+ await GetGridData();
}
- // Sample data follows below
+ // 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
+ {
+ private static List _data { get; set; } = new List();
- public IEnumerable SelectedItems { get; set; } = Enumerable.Empty();
+ public static async Task Create(SampleData itemToInsert)
+ {
+ itemToInsert.Id = _data.Count + 1;
+ _data.Insert(0, itemToInsert);
+ }
- public List GridData { get; set; } = Enumerable.Range(1, 30).Select(x => new SampleData
- {
- Id = x,
- Name = "name " + x,
- Team = "team " + x % 5
- }).ToList();
+ public static async Task> Read()
+ {
+ if (_data.Count < 1)
+ {
+ for (int i = 1; i < 50; i++)
+ {
+ _data.Add(new SampleData()
+ {
+ Id = i,
+ Name = "name " + i,
+ Team = "team " + i % 5
+ });
+ }
+ }
- public class SampleData
- {
- public int Id { get; set; }
- public string Name { get; set; }
- public string Team { get; set; }
+ return await Task.FromResult(_data);
+ }
- // example of comparing stored items (from editing or selection)
- // with items from the current data source - IDs are used instead of the default references
- public override bool Equals(object obj)
+ public static async Task Update(SampleData itemToUpdate)
{
- if (obj is SampleData)
+ var index = _data.FindIndex(i => i.Id == itemToUpdate.Id);
+ if (index != -1)
{
- return this.Id == (obj as SampleData).Id;
+ _data[index] = itemToUpdate;
}
- return false;
+ }
+
+ public static async Task Delete(SampleData itemToDelete)
+ {
+ _data.Remove(itemToDelete);
}
}
-}
+}****
````
````Service
using Microsoft.JSInterop;
@@ -532,7 +540,7 @@ In addition to that, you can also use the `EditItem`, `OriginalEditItem` and `In
````CSHTML
@* This example shows how to make the grid edit a certain item or start insert operation
through your own code, without requiring the user to click the Command buttons.
- The buttons that initiate these operations can be anywhere on the page, inlcuding inside the grid.
+ The buttons that initiate these operations can be anywhere on the page, including inside the grid.
Note the model constructors and static method that show how to get a new instance for the edit item
*@
@@ -567,8 +575,8 @@ In addition to that, you can also use the `EditItem`, `OriginalEditItem` and `In
// you can predefine values here as well (not mandatory)
currState.InsertedItem = new SampleData() { Name = "some predefined value" };
await GridRef.SetState(currState);
-
- // note: possible only for Inline and Popup edit modes, with InCell there is never an inserted item, only edited items
+
+ // note: possible only for Inline and Popup edit modes, with InCell there is never an inserted item, only edited items
}
async Task EditItemFour()
@@ -594,14 +602,10 @@ In addition to that, you can also use the `EditItem`, `OriginalEditItem` and `In
SampleData item = (SampleData)args.Item;
// perform actual data source operations here through your service
- SampleData updatedItem = await ServiceMimicUpdate(item);
+ await MyService.Update(item);
- // update the local view-model data
- var index = MyData.FindIndex(i => i.ID == updatedItem.ID);
- if (index != -1)
- {
- MyData[index] = updatedItem;
- }
+ // update the local view-model data with the service data
+ await GetGridData();
}
async Task DeleteHandler(GridCommandEventArgs args)
@@ -609,13 +613,10 @@ In addition to that, you can also use the `EditItem`, `OriginalEditItem` and `In
SampleData item = (SampleData)args.Item;
// perform actual data source operation here through your service
- bool isDeleted = await ServiceMimicDelete(item);
+ await MyService.Delete(item);
- if (isDeleted)
- {
- // update the local view-model data
- MyData.Remove(item);
- }
+ // update the local view-model data with the service data
+ await GetGridData();
}
async Task CreateHandler(GridCommandEventArgs args)
@@ -623,46 +624,10 @@ In addition to that, you can also use the `EditItem`, `OriginalEditItem` and `In
SampleData item = (SampleData)args.Item;
// perform actual data source operation here through your service
- SampleData insertedItem = await ServiceMimicInsert(item);
+ await MyService.Create(item);
- // update the local view-model data
- MyData.Insert(0, insertedItem);
- }
-
-
- // the following three methods mimic an actual data service that handles the actual data source
- // you can see about implement error and exception handling, determining suitable return types as per your needs
- // an example is available here: https://github.com/telerik/blazor-ui/tree/master/grid/remote-validation
-
- async Task ServiceMimicInsert(SampleData itemToInsert)
- {
- // in this example, we just populate the fields, you project may use
- // something else or generate the updated item differently
- SampleData updatedItem = new SampleData()
- {
- // the service assigns an ID, in this sample we use only the view-model data for simplicity,
- // you should use the actual data and set the properties as necessary (e.g., generate nested fields data and so on)
- ID = MyData.Count + 1,
- Name = itemToInsert.Name
- };
- return await Task.FromResult(updatedItem);
- }
-
- async Task ServiceMimicUpdate(SampleData itemToUpdate)
- {
- // in this example, we just populate the fields, you project may use
- // something else or generate the updated item differently
- SampleData updatedItem = new SampleData()
- {
- ID = itemToUpdate.ID,
- Name = itemToUpdate.Name
- };
- return await Task.FromResult(updatedItem);
- }
-
- async Task ServiceMimicDelete(SampleData itemToDelete)
- {
- return await Task.FromResult(true);//always successful
+ // update the local view-model data with the service data
+ await GetGridData();
}
// Sample class definition - note the constructors, overrides and comments
@@ -708,17 +673,57 @@ In addition to that, you can also use the `EditItem`, `OriginalEditItem` and `In
public List MyData { get; set; }
- protected override void OnInitialized()
+ async Task GetGridData()
+ {
+ MyData = await MyService.Read();
+ }
+
+ protected override async Task OnInitializedAsync()
+ {
+ await GetGridData();
+ }
+
+ // 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
{
- MyData = new List();
+ private static List _data { get; set; } = new List();
+
+ public static async Task Create(SampleData itemToInsert)
+ {
+ itemToInsert.ID = _data.Count + 1;
+ _data.Insert(0, itemToInsert);
+ }
- for (int i = 0; i < 50; i++)
+ public static async Task> Read()
{
- MyData.Add(new SampleData()
+ if (_data.Count < 1)
{
- ID = i,
- Name = "Name " + i.ToString()
- });
+ for (int i = 1; i < 50; i++)
+ {
+ _data.Add(new SampleData()
+ {
+ ID = i,
+ Name = "Name " + i.ToString()
+ });
+ }
+ }
+
+ return await Task.FromResult(_data);
+ }
+
+ public static async Task Update(SampleData itemToUpdate)
+ {
+ var index = _data.FindIndex(i => i.ID == itemToUpdate.ID);
+ if (index != -1)
+ {
+ _data[index] = itemToUpdate;
+ }
+ }
+
+ public static async Task Delete(SampleData itemToDelete)
+ {
+ _data.Remove(itemToDelete);
}
}
}
diff --git a/components/grid/templates/editor.md b/components/grid/templates/editor.md
index 8f2f42d283..101aba643e 100644
--- a/components/grid/templates/editor.md
+++ b/components/grid/templates/editor.md
@@ -54,66 +54,79 @@ You can find the following examples below:
@code {
- public SampleData CurrentlyEditedEmployee { get; set; }
+ List MyData { get; set; }
+ List Roles { get; set; }
+ SampleData CurrentlyEditedEmployee { get; set; }
public async Task UpdateHandler(GridCommandEventArgs args)
{
SampleData item = (SampleData)args.Item;
// perform actual data source operations here through your service
- SampleData updatedItem = await ServiceMimicUpdate(item);
+ await MyService.Update(item);
- // update the local view-model data
- var index = MyData.FindIndex(i => i.ID == updatedItem.ID);
- if (index != -1)
- {
- MyData[index] = updatedItem;
- }
+ // update the local view-model data with the service data
+ await GetGridData();
}
- // the following method mimics an actual data service that handles the actual data source
- // you can see about implement error and exception handling, determining suitable return types as per your needs
- // an example is available here: https://github.com/telerik/blazor-ui/tree/master/grid/remote-validation
+ //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; }
+ public string Name { get; set; }
+ public string Role { get; set; }
+ }
- async Task ServiceMimicUpdate(SampleData itemToUpdate)
+ async Task GetGridData()
{
- // in this example, we just populate the fields, you project may use
- // something else or generate the updated item differently
- SampleData updatedItem = new SampleData()
- {
- ID = itemToUpdate.ID,
- Name = itemToUpdate.Name,
- Role = itemToUpdate.Role
- };
- return await Task.FromResult(updatedItem);
+ MyData = await MyService.Read();
+ Roles = await MyService.GetRoles();
+ }
+
+ protected override async Task OnInitializedAsync()
+ {
+ await GetGridData();
}
- protected override void OnInitialized()
+ // 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
{
- MyData = new List();
+ private static List _data { get; set; } = new List();
+ private static List Roles = new List { "Manager", "Employee", "Contractor" };
- for (int i = 0; i < 50; i++)
+ public static async Task> Read()
{
- MyData.Add(new SampleData()
+ if (_data.Count < 1)
{
- ID = i,
- Name = "name " + i,
- Role = Roles[i % Roles.Count]
- });
- }
- }
+ for (int i = 1; i < 50; i++)
+ {
+ _data.Add(new SampleData()
+ {
+ ID = i,
+ Name = "Name " + i.ToString(),
+ Role = Roles[i % Roles.Count]
+ });
+ }
+ }
- //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; }
- public string Name { get; set; }
- public string Role { get; set; }
- }
+ return await Task.FromResult(_data);
+ }
- public List MyData { get; set; }
+ public static async Task> GetRoles()
+ {
+ return await Task.FromResult(Roles);
+ }
- public static List Roles = new List { "Manager", "Employee", "Contractor" };
+ public static async Task Update(SampleData itemToUpdate)
+ {
+ var index = _data.FindIndex(i => i.ID == itemToUpdate.ID);
+ if (index != -1)
+ {
+ _data[index] = itemToUpdate;
+ }
+ }
+ }
}
````
@@ -168,81 +181,84 @@ You can find the following examples below:
Employee item = (Employee)args.Item;
// perform actual data source operations here through your service
- Employee updatedItem = await ServiceMimicUpdate(item);
+ await MyService.Update(item);
- // update the local view-model data
- var index = MyData.FindIndex(i => i.ID == updatedItem.ID);
- if (index != -1)
- {
- MyData[index] = updatedItem;
- }
+ // update the local view-model data with the service data
+ await GetGridData();
}
- // the following method mimics an actual data service that handles the actual data source
- // you can see about implement error and exception handling, determining suitable return types as per your needs
- // an example is available here: https://github.com/telerik/blazor-ui/tree/master/grid/remote-validation
-
- async Task ServiceMimicUpdate(Employee itemToUpdate)
+ public class Employee
{
- // in this example, we just populate the fields, you project may use
- // something else or generate the updated item differently
- Employee updatedItem = new Employee()
- {
- ID = itemToUpdate.ID,
- Name = itemToUpdate.Name,
- RoleId = itemToUpdate.RoleId
- };
- return await Task.FromResult(updatedItem);
+ public int ID { get; set; }
+ public string Name { get; set; }
+ public int RoleId { get; set; }
}
- protected override async Task OnInitializedAsync()
+ public class Role
{
- Roles = await GetRoles();
- MyData = await GetGridData();
+ public int RoleId { get; set; }
+ public string RoleName { get; set; }
}
- async Task> GetRoles()
+ async Task GetGridData()
{
- var data = new List
- {
- new Role { RoleId = 1, RoleName = "Manager" },
- new Role { RoleId = 2, RoleName = "Employee" },
- new Role { RoleId = 3, RoleName = "Contractor" },
- };
+ MyData = await MyService.Read();
+ Roles = await MyService.GetRoles();
+ }
- return await Task.FromResult(data);
+ protected override async Task OnInitializedAsync()
+ {
+ await GetGridData();
}
- async Task> GetGridData()
+ // 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
{
- var data = new List();
- for (int i = 0; i < 50; i++)
+ private static List _data { get; set; } = new List();
+ private static List Roles = new List { "Manager", "Employee", "Contractor" };
+
+ public static async Task> Read()
{
- data.Add(new Employee()
+ if (_data.Count < 1)
{
- ID = i,
- Name = "name " + i,
- RoleId = i % 4 // every one in four is an unknown one that will not be present in the roles list
- // and will have an ID of 0 to match the DefaultText of the dropdownlist
- // you can perform more complicated checks as necessary in your app and/or in the templates
- // and/or in the view-model data to present it with suitable values and avoid exceptions
- });
+ for (int i = 0; i < 50; i++)
+ {
+ _data.Add(new Employee()
+ {
+ ID = i,
+ Name = "name " + i,
+ RoleId = i % 4 // every one in four is an unknown one that will not be present in the roles list
+ // and will have an ID of 0 to match the DefaultText of the dropdownlist
+ // you can perform more complicated checks as necessary in your app and/or in the templates
+ // and/or in the view-model data to present it with suitable values and avoid exceptions
+ });
+ }
+ }
+
+ return await Task.FromResult(_data);
}
- return await Task.FromResult(data);
- }
+ public static async Task> GetRoles()
+ {
+ var data = new List
+ {
+ new Role { RoleId = 1, RoleName = "Manager" },
+ new Role { RoleId = 2, RoleName = "Employee" },
+ new Role { RoleId = 3, RoleName = "Contractor" },
+ };
- public class Employee
- {
- public int ID { get; set; }
- public string Name { get; set; }
- public int RoleId { get; set; }
- }
+ return await Task.FromResult(data);
+ }
- public class Role
- {
- public int RoleId { get; set; }
- public string RoleName { get; set; }
+ public static async Task Update(Employee itemToUpdate)
+ {
+ var index = _data.FindIndex(i => i.ID == itemToUpdate.ID);
+ if (index != -1)
+ {
+ _data[index] = itemToUpdate;
+ }
+ }
}
}
````
diff --git a/components/grid/toolbar.md b/components/grid/toolbar.md
index 8f325fd702..c439864d26 100644
--- a/components/grid/toolbar.md
+++ b/components/grid/toolbar.md
@@ -40,6 +40,7 @@ The grid offers built-in commands that you can invoke through its toolbar. To us
Add Employee
+
@@ -52,20 +53,17 @@ The grid offers built-in commands that you can invoke through its toolbar. To us
@code {
string result;
+ public List MyData { get; set; }
private async Task UpdateHandler(GridCommandEventArgs args)
{
SampleData item = args.Item as SampleData;
// perform actual data source operations here through your service
- SampleData updatedItem = await ServiceMimicUpdate(item);
+ SampleData updatedItem = await MyService.Update(item);
- // update the local view-model data
- var index = MyData.FindIndex(i => i.ID == updatedItem.ID);
- if (index != -1)
- {
- MyData[index] = updatedItem;
- }
+ // update the local view-model data with the service data
+ await GetGridData();
result = string.Format("Employee with ID {0} now has name {1} and hire date {2}", updatedItem.ID, updatedItem.Name, updatedItem.HireDate);
}
@@ -74,67 +72,83 @@ The grid offers built-in commands that you can invoke through its toolbar. To us
{
SampleData item = args.Item as SampleData;
- // perform actual data source operation here through your service
- SampleData insertedItem = await ServiceMimicInsert(item);
+ // perform actual data source operations here through your service
+ SampleData insertedItem = await MyService.Create(item);
- // update the local view-model data
- MyData.Insert(0, insertedItem);
+ // update the local view-model data with the service data
+ await GetGridData();
result = string.Format("On {2} you added the employee {0} who was hired on {1}.", insertedItem.Name, insertedItem.HireDate, DateTime.Now);
}
- // the following two methods mimic an actual data service that handles the actual data source
- // you can see about implement error and exception handling, determining suitable return types as per your needs
- // an example is available here: https://github.com/telerik/blazor-ui/tree/master/grid/remote-validation
-
- async Task ServiceMimicInsert(SampleData itemToInsert)
+ //in a real case, keep the models in dedicated locations, this is just an easy to copy and see example
+ public class SampleData
{
- // in this example, we just populate the fields, you project may use
- // something else or generate the updated item differently
- SampleData updatedItem = new SampleData()
- {
- // the service assigns an ID, in this sample we use only the view-model data for simplicity,
- // you should use the actual data and set the properties as necessary (e.g., generate nested fields data and so on)
- ID = MyData.Count + 1,
- Name = itemToInsert.Name,
- HireDate = itemToInsert.HireDate
- };
- return await Task.FromResult(updatedItem);
+ public int ID { get; set; }
+ public string Name { get; set; }
+ public DateTime HireDate { get; set; }
}
- async Task ServiceMimicUpdate(SampleData itemToUpdate)
+ async Task GetGridData()
{
- // in this example, we just populate the fields, you project may use
- // something else or generate the updated item differently
- SampleData updatedItem = new SampleData()
- {
- ID = itemToUpdate.ID,
- Name = itemToUpdate.Name,
- HireDate = itemToUpdate.HireDate
- };
- return await Task.FromResult(updatedItem);
+ MyData = await MyService.Read();
}
- //in a real case, keep the models in dedicated locations, this is just an easy to copy and see example
- public class SampleData
+ protected override async Task OnInitializedAsync()
{
- public int ID { get; set; }
- public string Name { get; set; }
- public DateTime HireDate { get; set; }
+ await GetGridData();
}
- public List MyData = Enumerable.Range(1, 50).Select(x => new SampleData
+ // 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
{
- ID = x,
- Name = "name " + x,
- HireDate = DateTime.Now.AddDays(-x)
- }).ToList();
+ private static List _data { get; set; } = new List();
+
+ public static async Task Create(SampleData itemToInsert)
+ {
+ itemToInsert.ID = _data.Count + 1;
+ _data.Insert(0, itemToInsert);
+
+ return await Task.FromResult(itemToInsert);
+ }
+
+ public static async Task> Read()
+ {
+ if (_data.Count < 1)
+ {
+ for (int i = 1; i < 50; i++)
+ {
+ _data.Add(new SampleData()
+ {
+ ID = i,
+ Name = "Name " + i.ToString(),
+ HireDate = DateTime.Now.AddDays(-i)
+ });
+ }
+ }
+
+ return await Task.FromResult(_data);
+ }
+
+ public static async Task Update(SampleData itemToUpdate)
+ {
+ var index = _data.FindIndex(i => i.ID == itemToUpdate.ID);
+ if (index != -1)
+ {
+ _data[index] = itemToUpdate;
+ return await Task.FromResult(_data[index]);
+ }
+
+ throw new Exception("no item to update");
+ }
+ }
}
````
->caption The result from the code snippet above, after built-in Create button in the toolbar was clicked
+>caption The result from the code snippet above, after the built-in Create button in the toolbar was clicked
-
+
## Custom Commands
diff --git a/components/listview/editing.md b/components/listview/editing.md
index 8b8b61611d..bb672f85d8 100644
--- a/components/listview/editing.md
+++ b/components/listview/editing.md
@@ -62,19 +62,18 @@ The CUD operations are implemented through dedicated events that let you alter t
@code{
+ List ListViewData { get; set; }
+ List Teams { get; set; }
+
async Task UpdateHandler(ListViewCommandEventArgs args)
{
Employee item = (Employee)args.Item;
- // perform actual data source operations here through your service
- Employee updatedItem = await ServiceMimicUpdate(item);
+ // perform actual data source operation here through your service
+ await MyService.Update(item);
// update the local view-model data with the service data
- var index = ListViewData.FindIndex(i => i.Id == updatedItem.Id);
- if (index != -1)
- {
- ListViewData[index] = updatedItem;
- }
+ await GetListViewData();
}
async Task DeleteHandler(ListViewCommandEventArgs args)
@@ -82,13 +81,10 @@ The CUD operations are implemented through dedicated events that let you alter t
Employee item = (Employee)args.Item;
// perform actual data source operation here through your service
- bool isDeleted = await ServiceMimicDelete(item);
+ await MyService.Delete(item);
- if (isDeleted)
- {
- // update the local view-model data
- ListViewData.Remove(item);
- }
+ // update the local view-model data with the service data
+ await GetListViewData();
}
async Task CreateHandler(ListViewCommandEventArgs args)
@@ -96,10 +92,10 @@ The CUD operations are implemented through dedicated events that let you alter t
Employee item = (Employee)args.Item;
// perform actual data source operation here through your service
- Employee insertedItem = await ServiceMimicInsert(item);
+ await MyService.Create(item);
// update the local view-model data with the service data
- ListViewData.Insert(0, insertedItem);
+ await GetListViewData();
}
async Task EditHandler(ListViewCommandEventArgs e)
@@ -120,64 +116,75 @@ The CUD operations are implemented through dedicated events that let you alter t
Console.WriteLine($"user changed item {changedItem.Id} to have Name: {changedItem.Name} and Team: {changedItem.Team}");
}
- // the following three methods mimic an actual data service that handles the actual data source
- // you can see about implement error and exception handling, determining suitable return types as per your needs
- // an example is available here: https://github.com/telerik/blazor-ui/tree/master/grid/remote-validation
+ // data and models follow
- async Task ServiceMimicInsert(Employee itemToInsert)
+ async Task GetListViewData()
{
- // in this example, we just populate the fields, you project may use
- // something else or generate the updated item differently, we use "new" here
- Employee updatedItem = new Employee()
- {
- // the service assigns an ID, in this sample we use only the view-model data for simplicity,
- // you should use the actual data and set the properties as necessary (e.g., generate nested fields data and so on)
- Id = ListViewData.Count + 1,
- Name = itemToInsert.Name,
- Team = itemToInsert.Team
- };
- return await Task.FromResult(updatedItem);
+ ListViewData = await MyService.Read();
+ Teams = await MyService.GetTeams();
}
- async Task ServiceMimicUpdate(Employee itemToUpdate)
+ protected override async Task OnInitializedAsync()
{
- // in this example, we just populate the fields, you project may use
- // something else or generate the updated item differently
- Employee updatedItem = new Employee()
- {
- Id = itemToUpdate.Id,
- Name = itemToUpdate.Name,
- Team = itemToUpdate.Team
- };
- return await Task.FromResult(updatedItem);
+ await GetListViewData();
}
- async Task ServiceMimicDelete(Employee itemToDelete)
+ public class Employee
{
- return await Task.FromResult(true);//always successful
+ public int Id { get; set; }
+ public string Name { get; set; }
+ public string Team { get; set; }
}
- // data and models follow
+ // 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
+ {
+ private static List _data { get; set; } = new List();
+ private static List _teams = new List { "Sales", "Dev", "Support" };
- List ListViewData { get; set; }
+ public static async Task Create(Employee itemToInsert)
+ {
+ itemToInsert.Id = _data.Count + 1;
+ _data.Insert(0, itemToInsert);
+ }
- protected override void OnInitialized()
- {
- ListViewData = Enumerable.Range(1, 250).Select(x => new Employee
+ public static async Task> Read()
{
- Id = x,
- Name = $"Name {x}",
- Team = Teams[x % Teams.Count]
- }).ToList();
- }
+ if (_data.Count < 1)
+ {
+ for (int i = 1; i < 50; i++)
+ {
+ _data.Add(new Employee()
+ {
+ Id = i,
+ Name = $"Name {i}",
+ Team = _teams[i % _teams.Count]
+ });
+ }
+ }
+
+ return await Task.FromResult(_data);
+ }
- List Teams = new List { "Sales", "Dev", "Support" };
+ public static async Task> GetTeams()
+ {
+ return await Task.FromResult(_teams);
+ }
- public class Employee
- {
- public int Id { get; set; }
- public string Name { get; set; }
- public string Team { get; set; }
+ public static async Task Update(Employee itemToUpdate)
+ {
+ var index = _data.FindIndex(i => i.Id == itemToUpdate.Id);
+ if (index != -1)
+ {
+ _data[index] = itemToUpdate;
+ }
+ }
+
+ public static async Task Delete(Employee itemToDelete)
+ {
+ _data.Remove(itemToDelete);
+ }
}
}
````
diff --git a/components/scheduler/edit-appointments.md b/components/scheduler/edit-appointments.md
index 1e5d85c527..0ce9c802a7 100644
--- a/components/scheduler/edit-appointments.md
+++ b/components/scheduler/edit-appointments.md
@@ -96,8 +96,6 @@ The example below shows the signature of the event handlers so you can copy the
@* This sample implements only updates to the view model. Your app must also update the database in the CUD events.
This example uses the default field names for data binding *@
-There is a deliberate delay in the CUD operations in this sample to showcase their async nature
-
@code {
+ // sample data and scheduler settings
+ public SchedulerView CurrView { get; set; } = SchedulerView.Week;
+ public DateTime StartDate { get; set; } = new DateTime(2019, 12, 2);
+ public DateTime DayStart { get; set; } = new DateTime(2000, 1, 1, 8, 0, 0); //the time portion is important
+
+ List Appointments { get; set; }
+
async Task UpdateAppointment(SchedulerUpdateEventArgs args)
{
SchedulerAppointment item = (SchedulerAppointment)args.Item;
// perform actual data source operations here through your service
- SchedulerAppointment updatedItem = await ServiceMimicUpdate(item);
+ await MyService.Update(item);
// update the local view-model data with the service data
- var index = Appointments.FindIndex(i => i.Id == updatedItem.Id);
- if (index != -1)
- {
- Appointments[index] = updatedItem;
- }
+ await GetSchedulerData();
}
async Task AddAppointment(SchedulerCreateEventArgs args)
{
SchedulerAppointment item = args.Item as SchedulerAppointment;
- // perform actual data source operation here through your service
- SchedulerAppointment insertedItem = await ServiceMimicInsert(item);
+ // perform actual data source operations here through your service
+ await MyService.Create(item);
// update the local view-model data with the service data
- Appointments.Add(insertedItem);
+ await GetSchedulerData();
}
async Task DeleteAppointment(SchedulerDeleteEventArgs args)
{
SchedulerAppointment item = (SchedulerAppointment)args.Item;
- // perform actual data source operation here through your service
- bool isDeleted = await ServiceMimicDelete(item);
+ // perform actual data source operations here through your service
+ await MyService.Delete(item);
- if (isDeleted)
- {
- // update the local view-model data
- Appointments.Remove(item);
- }
+ // update the local view-model data with the service data
+ await GetSchedulerData();
// see the comments in the service mimic method below.
- // if you do perform additional data source updates, you may want to
- // also fetch the entire scheduler data anew to ensure correct and fresh data
- // this also applies to the other CUD methods above
- // something like the following can refresh the data
- // Appointments = await AppointmentService.GetData();
}
//Handlers for application logic flexibility
@@ -189,80 +182,40 @@ There is a deliberate delay in the CUD operations in this sample to showcase the
}
- // the following three methods mimic an actual data service that handles the actual data source
- // you can see about implement error and exception handling, determining suitable return types as per your needs
-
- async Task ServiceMimicInsert(SchedulerAppointment itemToInsert)
+ public class SchedulerAppointment
{
- await Task.Delay(1000); // simulate actual long running async operation
- // in this example, we just populate the fields, you project may use
- // something else or generate the updated item differently, we use "new" here
- SchedulerAppointment updatedItem = new SchedulerAppointment()
+ public Guid Id { get; set; }
+ public string Title { get; set; }
+ public string Description { get; set; }
+ public DateTime Start { get; set; }
+ public DateTime End { get; set; }
+ public bool IsAllDay { get; set; }
+ public string RecurrenceRule { get; set; }
+ public List RecurrenceExceptions { get; set; }
+ public Guid? RecurrenceId { get; set; }
+
+ public SchedulerAppointment()
{
- Id = Guid.NewGuid(),
- Title = itemToInsert.Title,
- Description = itemToInsert.Description,
- Start = itemToInsert.Start,
- End = itemToInsert.End,
- IsAllDay = itemToInsert.IsAllDay,
- RecurrenceExceptions = itemToInsert.RecurrenceExceptions,
- RecurrenceRule = itemToInsert.RecurrenceRule,
- RecurrenceId = itemToInsert.RecurrenceId
- };
- return await Task.FromResult(updatedItem);
+ Id = Guid.NewGuid();
+ }
}
- async Task ServiceMimicUpdate(SchedulerAppointment itemToUpdate)
+ async Task GetSchedulerData()
{
- await Task.Delay(1000); // simulate actual long running async operation
- // in this example, we just populate the fields, you project may use
- // something else or generate the updated item differently
- SchedulerAppointment updatedItem = new SchedulerAppointment()
- {
- Id = itemToUpdate.Id,
- Title = itemToUpdate.Title,
- Description = itemToUpdate.Description,
- Start = itemToUpdate.Start,
- End = itemToUpdate.End,
- IsAllDay = itemToUpdate.IsAllDay,
- RecurrenceExceptions = itemToUpdate.RecurrenceExceptions,
- RecurrenceRule = itemToUpdate.RecurrenceRule,
- RecurrenceId = itemToUpdate.RecurrenceId
- };
-
- return await Task.FromResult(updatedItem);
+ Appointments = await MyService.Read();
}
- async Task ServiceMimicDelete(SchedulerAppointment itemToDelete)
+ protected override async Task OnInitializedAsync()
{
- await Task.Delay(1000); // simulate actual long running async operation
-
-
- if (itemToDelete.RecurrenceId != null)
- {
- // a recurrence exception was deleted, you may want to update
- // the actual data source - an item where theItem.Id == item.RecurrenceId
- // and remove the current exception date from the list of its RecurrenceExceptions
- }
-
- if (!string.IsNullOrEmpty(itemToDelete.RecurrenceRule) && itemToDelete.RecurrenceExceptions?.Count > 0)
- {
- // a recurring appointment was deleted that had exceptions, you may want to
- // delete or update any exceptions from the data source - look for
- // items where theItem.RecurrenceId == item.Id
- }
-
- return await Task.FromResult(true);//always successful
+ await GetSchedulerData();
}
-
- // sample data and scheduler settings
- public SchedulerView CurrView { get; set; } = SchedulerView.Week;
- public DateTime StartDate { get; set; } = new DateTime(2019, 12, 2);
- public DateTime DayStart { get; set; } = new DateTime(2000, 1, 1, 8, 0, 0); //the time portion is important
-
- List Appointments = new List()
+ // 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
{
+ private static List _data { get; set; } = new List()
+ {
new SchedulerAppointment
{
Title = "Board meeting",
@@ -304,23 +257,45 @@ There is a deliberate delay in the CUD operations in this sample to showcase the
End = new DateTime(2019, 11, 27, 9, 30, 0),
RecurrenceRule = "FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR"
}
- };
+ };
- public class SchedulerAppointment
- {
- public Guid Id { get; set; }
- public string Title { get; set; }
- public string Description { get; set; }
- public DateTime Start { get; set; }
- public DateTime End { get; set; }
- public bool IsAllDay { get; set; }
- public string RecurrenceRule { get; set; }
- public List RecurrenceExceptions { get; set; }
- public Guid? RecurrenceId { get; set; }
+ public static async Task Create(SchedulerAppointment itemToInsert)
+ {
+ itemToInsert.Id = Guid.NewGuid();
+ _data.Insert(0, itemToInsert);
+ }
- public SchedulerAppointment()
+ public static async Task> Read()
{
- Id = Guid.NewGuid();
+ return await Task.FromResult(_data);
+ }
+
+ public static async Task Update(SchedulerAppointment itemToUpdate)
+ {
+ var index = _data.FindIndex(i => i.Id == itemToUpdate.Id);
+ if (index != -1)
+ {
+ _data[index] = itemToUpdate;
+ }
+ }
+
+ public static async Task Delete(SchedulerAppointment itemToDelete)
+ {
+ if (itemToDelete.RecurrenceId != null)
+ {
+ // a recurrence exception was deleted, you may want to update
+ // the rest of the data source - find an item where theItem.Id == itemToDelete.RecurrenceId
+ // and remove the current exception date from the list of its RecurrenceExceptions
+ }
+
+ if (!string.IsNullOrEmpty(itemToDelete.RecurrenceRule) && itemToDelete.RecurrenceExceptions?.Count > 0)
+ {
+ // a recurring appointment was deleted that had exceptions, you may want to
+ // delete or update any exceptions from the data source - look for
+ // items where theItem.RecurrenceId == itemToDelete.Id
+ }
+
+ _data.Remove(itemToDelete);
}
}
}
diff --git a/components/treelist/columns/auto-generated.md b/components/treelist/columns/auto-generated.md
index cb89c99dff..c66e38777e 100644
--- a/components/treelist/columns/auto-generated.md
+++ b/components/treelist/columns/auto-generated.md
@@ -333,11 +333,6 @@ This example shows how to:
@code {
public List Data { get; set; }
- protected override async Task OnInitializedAsync()
- {
- Data = await GetTreeListData();
- }
-
// sample models with annotations
public class Employee
@@ -380,78 +375,81 @@ This example shows how to:
var item = e.Item as Employee;
// perform actual data source operations here through your service
- Employee updatedItem = await ServiceMimicUpdate(item);
+ await MyService.Update(item);
// update the local view-model data with the service data
- var index = Data.FindIndex(x => x.Id == updatedItem.Id);
- if (index != -1)
- {
- // see the Equals override in the model - it ensures this is the same
- // object from the treelist point of view and its state
- Data[index] = updatedItem;
- }
+ await GetTreeListData();
}
- // the following method mimics an actual data service that handles the actual data source
- // you can see about implement error and exception handling, determining suitable return types as per your needs
+ // data generation
- async Task ServiceMimicUpdate(Employee itemToUpdate)
+ async Task GetTreeListData()
{
- // in this example, we just populate the fields, you project may use
- // something else or generate the updated item differently
- Employee updatedItem = new Employee()
- {
- Id = itemToUpdate.Id,
- ParentId = itemToUpdate.ParentId,
- Name = itemToUpdate.Name,
- EmailAddress = itemToUpdate.EmailAddress,
- HireDate = itemToUpdate.HireDate
- };
- return await Task.FromResult(updatedItem);
+ Data = await MyService.Read();
}
- // data generation
+ protected override async Task OnInitializedAsync()
+ {
+ await GetTreeListData();
+ }
- async Task> GetTreeListData()
+ // 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
{
- List data = new List();
+ private static List _data { get; set; } = new List();
- for (int i = 1; i < 15; i++)
+ public static async Task> Read()
{
- data.Add(new Employee
- {
- Id = i,
- ParentId = null,
- Name = $"root: {i}",
- HireDate = DateTime.Now.AddYears(-i)
- }); ;
-
- for (int j = 1; j < 4; j++)
+ if (_data.Count < 1)
{
- int currId = i * 100 + j;
- data.Add(new Employee
- {
- Id = currId,
- ParentId = i,
- Name = $"first level child {j} of {i}",
- HireDate = DateTime.Now.AddDays(-currId)
- });
-
- for (int k = 1; k < 3; k++)
+ for (int i = 1; i < 15; i++)
{
- int nestedId = currId * 1000 + k;
- data.Add(new Employee
+ _data.Add(new Employee
{
- Id = nestedId,
- ParentId = currId,
- Name = $"second level child {k} of {i} and {currId}",
- HireDate = DateTime.Now.AddMinutes(-nestedId)
+ Id = i,
+ ParentId = null,
+ Name = $"root: {i}",
+ HireDate = DateTime.Now.AddYears(-i)
}); ;
+
+ for (int j = 1; j < 4; j++)
+ {
+ int currId = i * 100 + j;
+ _data.Add(new Employee
+ {
+ Id = currId,
+ ParentId = i,
+ Name = $"first level child {j} of {i}",
+ HireDate = DateTime.Now.AddDays(-currId)
+ });
+
+ for (int k = 1; k < 3; k++)
+ {
+ int nestedId = currId * 1000 + k;
+ _data.Add(new Employee
+ {
+ Id = nestedId,
+ ParentId = currId,
+ Name = $"second level child {k} of {i} and {currId}",
+ HireDate = DateTime.Now.AddMinutes(-nestedId)
+ }); ;
+ }
+ }
}
}
+
+ return await Task.FromResult(_data);
}
- return await Task.FromResult(data);
+ public static async Task Update(Employee itemToUpdate)
+ {
+ var index = _data.FindIndex(i => i.Id == itemToUpdate.Id);
+ if (index != -1)
+ {
+ _data[index] = itemToUpdate;
+ }
+ }
}
}
````
diff --git a/components/treelist/columns/command.md b/components/treelist/columns/command.md
index a887788181..d35e24802d 100644
--- a/components/treelist/columns/command.md
+++ b/components/treelist/columns/command.md
@@ -76,8 +76,6 @@ The `OnClick` handler of the commands receives an argument of type `TreeListComm
@code {
public List Data { get; set; }
- public static List Roles = new List { "Manager", "Employee", "Contractor" };
- public Employee CurrentlyEditedEmployee { get; set; }
// Sample CUD operations for the local data
async Task UpdateItem(TreeListCommandEventArgs args)
@@ -85,10 +83,10 @@ The `OnClick` handler of the commands receives an argument of type `TreeListComm
var item = args.Item as Employee; // you can also use the entire model
// perform actual data source operations here through your service
- Employee updatedItem = await ServiceMimicUpdate(item);
+ await MyService.Update(item);
// update the local view-model data with the service data
- UpdateItemRecursive(Data, updatedItem);
+ await GetTreeListData();
}
// sample custom command handling
@@ -115,45 +113,6 @@ The `OnClick` handler of the commands receives an argument of type `TreeListComm
await Task.Delay(2000); //simulate actual long running async operation
}
- // sample helper methods for handling the view-model data hierarchy
- void UpdateItemRecursive(List items, Employee itemToUpdate)
- {
- for (int i = 0; i < items.Count; i++)
- {
- if (items[i].Id.Equals(itemToUpdate.Id))
- {
- items[i] = itemToUpdate;
- return;
- }
-
- if (items[i].DirectReports?.Count > 0)
- {
- UpdateItemRecursive(items[i].DirectReports, itemToUpdate);
- }
- }
- }
-
-
- // the following method mimics an actual data service that handles the actual data source
- // you can see about implement error and exception handling, determining suitable return types as per your needs
-
- async Task ServiceMimicUpdate(Employee itemToUpdate)
- {
- // in this example, we just populate the fields, you project may use
- // something else or generate the updated item differently
- Employee updatedItem = new Employee()
- {
- Id = itemToUpdate.Id,
- Name = itemToUpdate.Name,
- EmailAddress = itemToUpdate.EmailAddress,
- HireDate = itemToUpdate.HireDate,
- HasChildren = itemToUpdate.HasChildren,
- DirectReports = itemToUpdate.DirectReports
- };
- return await Task.FromResult(updatedItem);
- }
-
-
// sample model
public class Employee
@@ -180,69 +139,104 @@ The `OnClick` handler of the commands receives an argument of type `TreeListComm
}
}
-
// data generation
- // used in this example for data generation and retrieval for CUD operations on the current view-model data
- public int LastId { get; set; } = 1;
+ async Task GetTreeListData()
+ {
+ Data = await MyService.Read();
+ }
protected override async Task OnInitializedAsync()
{
- Data = await GetTreeListData();
+ await GetTreeListData();
}
- async Task> GetTreeListData()
+ // 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
{
- List data = new List();
+ private static List _data { get; set; } = new List();
+ // used in this example for data generation and retrieval for CUD operations on the current view-model data
+ private static int LastId { get; set; } = 1;
+ private static List Roles = new List { "Manager", "Employee", "Contractor" };
- for (int i = 1; i < 15; i++)
+ public static async Task> Read()
{
- Employee root = new Employee
- {
- Id = LastId,
- Name = $"root: {i}",
- Role = Roles[i % Roles.Count],
- EmailAddress = $"{i}@example.com",
- HireDate = DateTime.Now.AddYears(-i),
- DirectReports = new List(),
- HasChildren = true
- };
- data.Add(root);
- LastId++;
-
- for (int j = 1; j < 4; j++)
+ if (_data.Count < 1)
{
- int currId = LastId;
- Employee firstLevelChild = new Employee
- {
- Id = currId,
- Name = $"first level child {j} of {i}",
- Role = Roles[j % Roles.Count],
- EmailAddress = $"{currId}@example.com",
- HireDate = DateTime.Now.AddDays(-currId),
- DirectReports = new List(),
- HasChildren = true
- };
- root.DirectReports.Add(firstLevelChild);
- LastId++;
-
- for (int k = 1; k < 3; k++)
+ for (int i = 1; i < 15; i++)
{
- int nestedId = LastId;
- firstLevelChild.DirectReports.Add(new Employee
+ Employee root = new Employee
{
Id = LastId,
- Name = $"second level child {k} of {j} and {i}",
- Role = Roles[k % Roles.Count],
- EmailAddress = $"{nestedId}@example.com",
- HireDate = DateTime.Now.AddMinutes(-nestedId)
- }); ;
+ Name = $"root: {i}",
+ Role = Roles[i % Roles.Count],
+ EmailAddress = $"{i}@example.com",
+ HireDate = DateTime.Now.AddYears(-i),
+ DirectReports = new List(),
+ HasChildren = true
+ };
+ _data.Add(root);
LastId++;
+
+ for (int j = 1; j < 4; j++)
+ {
+ int currId = LastId;
+ Employee firstLevelChild = new Employee
+ {
+ Id = currId,
+ Name = $"first level child {j} of {i}",
+ Role = Roles[j % Roles.Count],
+ EmailAddress = $"{currId}@example.com",
+ HireDate = DateTime.Now.AddDays(-currId),
+ DirectReports = new List(),
+ HasChildren = true
+ };
+ root.DirectReports.Add(firstLevelChild);
+ LastId++;
+
+ for (int k = 1; k < 3; k++)
+ {
+ int nestedId = LastId;
+ firstLevelChild.DirectReports.Add(new Employee
+ {
+ Id = LastId,
+ Name = $"second level child {k} of {j} and {i}",
+ Role = Roles[k % Roles.Count],
+ EmailAddress = $"{nestedId}@example.com",
+ HireDate = DateTime.Now.AddMinutes(-nestedId)
+ }); ;
+ LastId++;
+ }
+ }
}
}
+
+ return await Task.FromResult(_data);
+ }
+
+ public static async Task Update(Employee itemToUpdate)
+ {
+ UpdateItemRecursive(_data, itemToUpdate);
}
- return await Task.FromResult(data);
+ // sample helper methods for handling the view-model data hierarchy
+ private static void UpdateItemRecursive(List items, Employee itemToUpdate)
+ {
+ for (int i = 0; i < items.Count; i++)
+ {
+ if (items[i].Id.Equals(itemToUpdate.Id))
+ {
+ items[i] = itemToUpdate;
+ return;
+ }
+
+ if (items[i].DirectReports?.Count > 0)
+ {
+ UpdateItemRecursive(items[i].DirectReports, itemToUpdate);
+ }
+ }
+ }
}
}
````
diff --git a/components/treelist/editing/incell.md b/components/treelist/editing/incell.md
index bddfedb79f..feca579a89 100644
--- a/components/treelist/editing/incell.md
+++ b/components/treelist/editing/incell.md
@@ -44,9 +44,8 @@ Editing is cancelled for the first record.
Add
-
+
Add Child
- Edit
Delete
Update
Cancel
@@ -71,21 +70,22 @@ Editing is cancelled for the first record.
var item = args.Item as Employee; // you can also use the entire model
// perform actual data source operations here through your service
- Employee updatedItem = await ServiceMimicUpdate(item);
+ await MyService.Update(item);
// update the local view-model data with the service data
- UpdateItemRecursive(Data, updatedItem);
+ await GetTreeListData();
}
async Task CreateItem(TreeListCommandEventArgs args)
{
- var argsItem = args.Item as Employee;
+ var item = args.Item as Employee;
+ var parentItem = args.ParentItem as Employee;
- // perform actual data source operation here through your service
- Employee insertedItem = await ServiceMimicInsert(argsItem);
+ // perform actual data source operations here through your service
+ await MyService.Create(item, parentItem);
// update the local view-model data with the service data
- InsertItemRecursive(Data, insertedItem, args);
+ await GetTreeListData();
}
async Task DeleteItem(TreeListCommandEventArgs args)
@@ -93,73 +93,10 @@ Editing is cancelled for the first record.
var item = args.Item as Employee;
// perform actual data source operations here through your service
- bool isDeleted = await ServiceMimicDelete(item);
-
- if (isDeleted)
- {
- // update the local view-model data
- RemoveChildRecursive(Data, item);
- }
- }
-
- // sample helper methods for handling the view-model data hierarchy
- void InsertItemRecursive(List Data, Employee insertedItem, TreeListCommandEventArgs args)
- {
- if (args.ParentItem != null)
- {
- var parent = (Employee)args.ParentItem;
-
- parent.HasChildren = true;
- if (parent.DirectReports == null)
- {
- parent.DirectReports = new List();
- }
-
- parent.DirectReports.Insert(0, insertedItem);
- }
- else
- {
- Data.Insert(0, insertedItem);
- }
- }
-
- void UpdateItemRecursive(List items, Employee itemToUpdate)
- {
- for (int i = 0; i < items.Count; i++)
- {
- if (items[i].Id.Equals(itemToUpdate.Id))
- {
- items[i] = itemToUpdate;
- return;
- }
-
- if (items[i].DirectReports?.Count > 0)
- {
- UpdateItemRecursive(items[i].DirectReports, itemToUpdate);
- }
- }
- }
+ await MyService.Delete(item);
- void RemoveChildRecursive(List items, Employee item)
- {
- for (int i = 0; i < items.Count(); i++)
- {
- if (item.Equals(items[i]))
- {
- items.Remove(item);
-
- return;
- }
- else if (items[i].DirectReports?.Count > 0)
- {
- RemoveChildRecursive(items[i].DirectReports, item);
-
- if (items[i].DirectReports.Count == 0)
- {
- items[i].HasChildren = false;
- }
- }
- }
+ // update the local view-model data with the service data
+ await GetTreeListData();
}
// OnEdit handler
@@ -184,49 +121,6 @@ Editing is cancelled for the first record.
}
- // the following three methods mimic an actual data service that handles the actual data source
- // you can see about implement error and exception handling, determining suitable return types as per your needs
-
- async Task ServiceMimicInsert(Employee itemToInsert)
- {
- // in this example, we just populate the fields, you project may use
- // something else or generate the updated item differently, we use "new" here
- Employee insertedItem = new Employee()
- {
- // the service assigns an ID, in this sample we use only the view-model data for simplicity,
- // you should use the actual data and set the properties as necessary (e.g., generate nested fields data and so on)
- Id = LastId++,
- Name = itemToInsert.Name,
- EmailAddress = itemToInsert.EmailAddress,
- HireDate = itemToInsert.HireDate,
- HasChildren = itemToInsert.HasChildren,
- DirectReports = itemToInsert.DirectReports
- };
- return await Task.FromResult(insertedItem);
- }
-
- async Task ServiceMimicUpdate(Employee itemToUpdate)
- {
- // in this example, we just populate the fields, you project may use
- // something else or generate the updated item differently
- Employee updatedItem = new Employee()
- {
- Id = itemToUpdate.Id,
- Name = itemToUpdate.Name,
- EmailAddress = itemToUpdate.EmailAddress,
- HireDate = itemToUpdate.HireDate,
- HasChildren = itemToUpdate.HasChildren,
- DirectReports = itemToUpdate.DirectReports
- };
- return await Task.FromResult(updatedItem);
- }
-
- async Task ServiceMimicDelete(Employee itemToDelete)
- {
- return await Task.FromResult(true);//always successful
- }
-
-
// sample model
public class Employee
@@ -253,65 +147,152 @@ Editing is cancelled for the first record.
}
// data generation
- // used in this example for data generation and assigning an ID to newly inserted items
- public int LastId { get; set; } = 1;
+
+ async Task GetTreeListData()
+ {
+ Data = await MyService.Read();
+ }
protected override async Task OnInitializedAsync()
{
- Data = await GetTreeListData();
+ await GetTreeListData();
}
- async Task> GetTreeListData()
+ // 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
{
- List data = new List();
+ private static List _data { get; set; } = new List();
+ // used in this example for data generation and retrieval for CUD operations on the current view-model data
+ private static int LastId { get; set; } = 1;
- for (int i = 1; i < 15; i++)
+ public static async Task Create(Employee itemToInsert, Employee parentItem)
{
- Employee root = new Employee
- {
- Id = LastId,
- Name = $"root: {i}",
- EmailAddress = $"{i}@example.com",
- HireDate = DateTime.Now.AddYears(-i),
- DirectReports = new List(),
- HasChildren = true
- };
- data.Add(root);
- LastId++;
-
- for (int j = 1; j < 4; j++)
+ InsertItemRecursive(_data, itemToInsert, parentItem);
+ }
+
+ public static async Task> Read()
+ {
+ if (_data.Count < 1)
{
- int currId = LastId;
- Employee firstLevelChild = new Employee
+ for (int i = 1; i < 15; i++)
{
- Id = currId,
- Name = $"first level child {j} of {i}",
- EmailAddress = $"{currId}@example.com",
- HireDate = DateTime.Now.AddDays(-currId),
- DirectReports = new List(),
- HasChildren = true
- };
- root.DirectReports.Add(firstLevelChild);
- LastId++;
-
- for (int k = 1; k < 3; k++)
- {
- int nestedId = LastId;
- firstLevelChild.DirectReports.Add(new Employee
+ Employee root = new Employee
{
Id = LastId,
- Name = $"second level child {k} of {j} and {i}",
- EmailAddress = $"{nestedId}@example.com",
- HireDate = DateTime.Now.AddMinutes(-nestedId)
- }); ;
+ Name = $"root: {i}",
+ EmailAddress = $"{i}@example.com",
+ HireDate = DateTime.Now.AddYears(-i),
+ DirectReports = new List(),
+ HasChildren = true
+ };
+ _data.Add(root);
LastId++;
+
+ for (int j = 1; j < 4; j++)
+ {
+ int currId = LastId;
+ Employee firstLevelChild = new Employee
+ {
+ Id = currId,
+ Name = $"first level child {j} of {i}",
+ EmailAddress = $"{currId}@example.com",
+ HireDate = DateTime.Now.AddDays(-currId),
+ DirectReports = new List(),
+ HasChildren = true
+ };
+ root.DirectReports.Add(firstLevelChild);
+ LastId++;
+
+ for (int k = 1; k < 3; k++)
+ {
+ int nestedId = LastId;
+ firstLevelChild.DirectReports.Add(new Employee
+ {
+ Id = LastId,
+ Name = $"second level child {k} of {j} and {i}",
+ EmailAddress = $"{nestedId}@example.com",
+ HireDate = DateTime.Now.AddMinutes(-nestedId)
+ }); ;
+ LastId++;
+ }
+ }
}
+
+ _data[0].Name += " (non-editable, see OnEdit)";
}
+
+ return await Task.FromResult(_data);
}
- data[0].Name += " (non-editable, see OnEdit)";
+ public static async Task Update(Employee itemToUpdate)
+ {
+ UpdateItemRecursive(_data, itemToUpdate);
+ }
- return await Task.FromResult(data);
+ public static async Task Delete(Employee itemToDelete)
+ {
+ RemoveChildRecursive(_data, itemToDelete);
+ }
+
+ // sample helper methods for handling the view-model data hierarchy
+ static void UpdateItemRecursive(List items, Employee itemToUpdate)
+ {
+ for (int i = 0; i < items.Count; i++)
+ {
+ if (items[i].Id.Equals(itemToUpdate.Id))
+ {
+ items[i] = itemToUpdate;
+ return;
+ }
+
+ if (items[i].DirectReports?.Count > 0)
+ {
+ UpdateItemRecursive(items[i].DirectReports, itemToUpdate);
+ }
+ }
+ }
+
+ static void RemoveChildRecursive(List items, Employee item)
+ {
+ for (int i = 0; i < items.Count(); i++)
+ {
+ if (item.Equals(items[i]))
+ {
+ items.Remove(item);
+
+ return;
+ }
+ else if (items[i].DirectReports?.Count > 0)
+ {
+ RemoveChildRecursive(items[i].DirectReports, item);
+
+ if (items[i].DirectReports.Count == 0)
+ {
+ items[i].HasChildren = false;
+ }
+ }
+ }
+ }
+
+ static void InsertItemRecursive(List Data, Employee insertedItem, Employee parentItem)
+ {
+ insertedItem.Id = LastId++;
+ if (parentItem != null)
+ {
+ parentItem.HasChildren = true;
+ if (parentItem.DirectReports == null)
+ {
+ parentItem.DirectReports = new List();
+ }
+
+ parentItem.DirectReports.Insert(0, insertedItem);
+ }
+ else
+ {
+ Data.Insert(0, insertedItem);
+ }
+ }
}
}
````
diff --git a/components/treelist/editing/inline.md b/components/treelist/editing/inline.md
index 2e9e31e431..7eeb45245d 100644
--- a/components/treelist/editing/inline.md
+++ b/components/treelist/editing/inline.md
@@ -53,6 +53,7 @@ Editing is cancelled for the first record.
+
@code {
public List Data { get; set; }
@@ -62,21 +63,22 @@ Editing is cancelled for the first record.
var item = args.Item as Employee;
// perform actual data source operations here through your service
- Employee updatedItem = await ServiceMimicUpdate(item);
+ await MyService.Update(item);
// update the local view-model data with the service data
- UpdateItemRecursive(Data, updatedItem);
+ await GetTreeListData();
}
async Task CreateItem(TreeListCommandEventArgs args)
{
- var argsItem = args.Item as Employee;
+ var item = args.Item as Employee;
+ var parentItem = args.ParentItem as Employee;
- // perform actual data source operation here through your service
- Employee insertedItem = await ServiceMimicInsert(argsItem);
+ // perform actual data source operations here through your service
+ await MyService.Create(item, parentItem);
// update the local view-model data with the service data
- InsertItemRecursive(Data, insertedItem, args);
+ await GetTreeListData();
}
async Task DeleteItem(TreeListCommandEventArgs args)
@@ -84,73 +86,10 @@ Editing is cancelled for the first record.
var item = args.Item as Employee;
// perform actual data source operations here through your service
- bool isDeleted = await ServiceMimicDelete(item);
-
- if (isDeleted)
- {
- // update the local view-model data
- RemoveChildRecursive(Data, item);
- }
- }
-
- // sample helper methods for handling the view-model data hierarchy
- void InsertItemRecursive(List Data, Employee insertedItem, TreeListCommandEventArgs args)
- {
- if (args.ParentItem != null)
- {
- var parent = (Employee)args.ParentItem;
-
- parent.HasChildren = true;
- if (parent.DirectReports == null)
- {
- parent.DirectReports = new List();
- }
-
- parent.DirectReports.Insert(0, insertedItem);
- }
- else
- {
- Data.Insert(0, insertedItem);
- }
- }
-
- void UpdateItemRecursive(List items, Employee itemToUpdate)
- {
- for (int i = 0; i < items.Count; i++)
- {
- if (items[i].Id.Equals(itemToUpdate.Id))
- {
- items[i] = itemToUpdate;
- return;
- }
-
- if (items[i].DirectReports?.Count > 0)
- {
- UpdateItemRecursive(items[i].DirectReports, itemToUpdate);
- }
- }
- }
-
- void RemoveChildRecursive(List items, Employee item)
- {
- for (int i = 0; i < items.Count(); i++)
- {
- if (item.Equals(items[i]))
- {
- items.Remove(item);
+ await MyService.Delete(item);
- return;
- }
- else if (items[i].DirectReports?.Count > 0)
- {
- RemoveChildRecursive(items[i].DirectReports, item);
-
- if (items[i].DirectReports.Count == 0)
- {
- items[i].HasChildren = false;
- }
- }
- }
+ // update the local view-model data with the service data
+ await GetTreeListData();
}
// OnEdit handler
@@ -174,48 +113,6 @@ Editing is cancelled for the first record.
// if necessary, perform actual data source operation here through your service
}
- // the following three methods mimic an actual data service that handles the actual data source
- // you can see about implement error and exception handling, determining suitable return types as per your needs
-
- async Task ServiceMimicInsert(Employee itemToInsert)
- {
- // in this example, we just populate the fields, you project may use
- // something else or generate the updated item differently, we use "new" here
- Employee insertedItem = new Employee()
- {
- // the service assigns an ID, in this sample we use only the view-model data for simplicity,
- // you should use the actual data and set the properties as necessary (e.g., generate nested fields data and so on)
- Id = LastId++,
- Name = itemToInsert.Name,
- EmailAddress = itemToInsert.EmailAddress,
- HireDate = itemToInsert.HireDate,
- HasChildren = itemToInsert.HasChildren,
- DirectReports = itemToInsert.DirectReports
- };
- return await Task.FromResult(insertedItem);
- }
-
- async Task ServiceMimicUpdate(Employee itemToUpdate)
- {
- // in this example, we just populate the fields, you project may use
- // something else or generate the updated item differently
- Employee updatedItem = new Employee()
- {
- Id = itemToUpdate.Id,
- Name = itemToUpdate.Name,
- EmailAddress = itemToUpdate.EmailAddress,
- HireDate = itemToUpdate.HireDate,
- HasChildren = itemToUpdate.HasChildren,
- DirectReports = itemToUpdate.DirectReports
- };
- return await Task.FromResult(updatedItem);
- }
-
- async Task ServiceMimicDelete(Employee itemToDelete)
- {
- return await Task.FromResult(true);//always successful
- }
-
// sample model
@@ -243,65 +140,152 @@ Editing is cancelled for the first record.
}
// data generation
- // used in this example for data generation and assigning an ID to newly inserted items
- public int LastId { get; set; } = 1;
+
+ async Task GetTreeListData()
+ {
+ Data = await MyService.Read();
+ }
protected override async Task OnInitializedAsync()
{
- Data = await GetTreeListData();
+ await GetTreeListData();
}
- async Task> GetTreeListData()
+ // 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
{
- List data = new List();
+ private static List _data { get; set; } = new List();
+ // used in this example for data generation and retrieval for CUD operations on the current view-model data
+ private static int LastId { get; set; } = 1;
- for (int i = 1; i < 15; i++)
+ public static async Task Create(Employee itemToInsert, Employee parentItem)
{
- Employee root = new Employee
- {
- Id = LastId,
- Name = $"root: {i}",
- EmailAddress = $"{i}@example.com",
- HireDate = DateTime.Now.AddYears(-i),
- DirectReports = new List(),
- HasChildren = true
- };
- data.Add(root);
- LastId++;
-
- for (int j = 1; j < 4; j++)
+ InsertItemRecursive(_data, itemToInsert, parentItem);
+ }
+
+ public static async Task> Read()
+ {
+ if (_data.Count < 1)
{
- int currId = LastId;
- Employee firstLevelChild = new Employee
- {
- Id = currId,
- Name = $"first level child {j} of {i}",
- EmailAddress = $"{currId}@example.com",
- HireDate = DateTime.Now.AddDays(-currId),
- DirectReports = new List(),
- HasChildren = true
- };
- root.DirectReports.Add(firstLevelChild);
- LastId++;
-
- for (int k = 1; k < 3; k++)
+ for (int i = 1; i < 15; i++)
{
- int nestedId = LastId;
- firstLevelChild.DirectReports.Add(new Employee
+ Employee root = new Employee
{
Id = LastId,
- Name = $"second level child {k} of {j} and {i}",
- EmailAddress = $"{nestedId}@example.com",
- HireDate = DateTime.Now.AddMinutes(-nestedId)
- }); ;
+ Name = $"root: {i}",
+ EmailAddress = $"{i}@example.com",
+ HireDate = DateTime.Now.AddYears(-i),
+ DirectReports = new List(),
+ HasChildren = true
+ };
+ _data.Add(root);
LastId++;
+
+ for (int j = 1; j < 4; j++)
+ {
+ int currId = LastId;
+ Employee firstLevelChild = new Employee
+ {
+ Id = currId,
+ Name = $"first level child {j} of {i}",
+ EmailAddress = $"{currId}@example.com",
+ HireDate = DateTime.Now.AddDays(-currId),
+ DirectReports = new List(),
+ HasChildren = true
+ };
+ root.DirectReports.Add(firstLevelChild);
+ LastId++;
+
+ for (int k = 1; k < 3; k++)
+ {
+ int nestedId = LastId;
+ firstLevelChild.DirectReports.Add(new Employee
+ {
+ Id = LastId,
+ Name = $"second level child {k} of {j} and {i}",
+ EmailAddress = $"{nestedId}@example.com",
+ HireDate = DateTime.Now.AddMinutes(-nestedId)
+ }); ;
+ LastId++;
+ }
+ }
+ }
+
+ _data[0].Name += " (non-editable, see OnEdit)";
+ }
+
+ return await Task.FromResult(_data);
+ }
+
+ public static async Task Update(Employee itemToUpdate)
+ {
+ UpdateItemRecursive(_data, itemToUpdate);
+ }
+
+ public static async Task Delete(Employee itemToDelete)
+ {
+ RemoveChildRecursive(_data, itemToDelete);
+ }
+
+ // sample helper methods for handling the view-model data hierarchy
+ static void UpdateItemRecursive(List items, Employee itemToUpdate)
+ {
+ for (int i = 0; i < items.Count; i++)
+ {
+ if (items[i].Id.Equals(itemToUpdate.Id))
+ {
+ items[i] = itemToUpdate;
+ return;
+ }
+
+ if (items[i].DirectReports?.Count > 0)
+ {
+ UpdateItemRecursive(items[i].DirectReports, itemToUpdate);
}
}
}
- data[0].Name += " (non-editable, see OnEdit)";
+ static void RemoveChildRecursive(List items, Employee item)
+ {
+ for (int i = 0; i < items.Count(); i++)
+ {
+ if (item.Equals(items[i]))
+ {
+ items.Remove(item);
+
+ return;
+ }
+ else if (items[i].DirectReports?.Count > 0)
+ {
+ RemoveChildRecursive(items[i].DirectReports, item);
- return await Task.FromResult(data);
+ if (items[i].DirectReports.Count == 0)
+ {
+ items[i].HasChildren = false;
+ }
+ }
+ }
+ }
+
+ static void InsertItemRecursive(List Data, Employee insertedItem, Employee parentItem)
+ {
+ insertedItem.Id = LastId++;
+ if (parentItem != null)
+ {
+ parentItem.HasChildren = true;
+ if (parentItem.DirectReports == null)
+ {
+ parentItem.DirectReports = new List();
+ }
+
+ parentItem.DirectReports.Insert(0, insertedItem);
+ }
+ else
+ {
+ Data.Insert(0, insertedItem);
+ }
+ }
}
}
````
diff --git a/components/treelist/editing/overview.md b/components/treelist/editing/overview.md
index 76f6b25098..75854b52a2 100644
--- a/components/treelist/editing/overview.md
+++ b/components/treelist/editing/overview.md
@@ -53,6 +53,9 @@ The example below shows how you can handle the events the treelist exposes, so y
>caption Handling the CRUD events of the treelist to save data to the actual data source
````CSHTML
+@using System.ComponentModel.DataAnnotations
+@* Used for the model annotations only *@
+
Editing is cancelled for the first record.
@@ -96,23 +99,24 @@ Editing is cancelled for the first record.
var item = args.Item as Employee;
// perform actual data source operations here through your service
- Employee updatedItem = await ServiceMimicUpdate(item);
+ await MyService.Update(item);
// update the local view-model data with the service data
- UpdateItemRecursive(Data, updatedItem);
+ await GetTreeListData();
AppendToLog("Update", args);
}
async Task CreateItem(TreeListCommandEventArgs args)
{
- var argsItem = args.Item as Employee;
+ var item = args.Item as Employee;
+ var parentItem = args.ParentItem as Employee;
- // perform actual data source operation here through your service
- Employee insertedItem = await ServiceMimicInsert(argsItem);
+ // perform actual data source operations here through your service
+ await MyService.Create(item, parentItem);
// update the local view-model data with the service data
- InsertItemRecursive(Data, insertedItem, args);
+ await GetTreeListData();
AppendToLog("Create", args);
}
@@ -122,78 +126,14 @@ Editing is cancelled for the first record.
var item = args.Item as Employee;
// perform actual data source operations here through your service
- bool isDeleted = await ServiceMimicDelete(item);
+ await MyService.Delete(item);
- if (isDeleted)
- {
- // update the local view-model data
- RemoveChildRecursive(Data, item);
- }
+ // update the local view-model data with the service data
+ await GetTreeListData();
AppendToLog("Delete", args);
}
-
- // sample helper methods for handling the view-model data hierarchy
- void InsertItemRecursive(List Data, Employee insertedItem, TreeListCommandEventArgs args)
- {
- if (args.ParentItem != null)
- {
- var parent = (Employee)args.ParentItem;
-
- parent.HasChildren = true;
- if (parent.DirectReports == null)
- {
- parent.DirectReports = new List();
- }
-
- parent.DirectReports.Insert(0, insertedItem);
- }
- else
- {
- Data.Insert(0, insertedItem);
- }
- }
-
- void UpdateItemRecursive(List items, Employee itemToUpdate)
- {
- for (int i = 0; i < items.Count; i++)
- {
- if (items[i].Id.Equals(itemToUpdate.Id))
- {
- items[i] = itemToUpdate;
- return;
- }
-
- if (items[i].DirectReports?.Count > 0)
- {
- UpdateItemRecursive(items[i].DirectReports, itemToUpdate);
- }
- }
- }
-
- void RemoveChildRecursive(List items, Employee item)
- {
- for (int i = 0; i < items.Count(); i++)
- {
- if (item.Equals(items[i]))
- {
- items.Remove(item);
-
- return;
- }
- else if (items[i].DirectReports?.Count > 0)
- {
- RemoveChildRecursive(items[i].DirectReports, item);
-
- if (items[i].DirectReports.Count == 0)
- {
- items[i].HasChildren = false;
- }
- }
- }
- }
-
// OnEdit handler
async Task OnEditHandler(TreeListCommandEventArgs args)
@@ -219,49 +159,6 @@ Editing is cancelled for the first record.
AppendToLog("Cancel", args);
}
- // the following three methods mimic an actual data service that handles the actual data source
- // you can see about implement error and exception handling, determining suitable return types as per your needs
-
- async Task ServiceMimicInsert(Employee itemToInsert)
- {
- // in this example, we just populate the fields, you project may use
- // something else or generate the updated item differently, we use "new" here
- Employee insertedItem = new Employee()
- {
- // the service assigns an ID, in this sample we use only the view-model data for simplicity,
- // you should use the actual data and set the properties as necessary (e.g., generate nested fields data and so on)
- Id = LastId++,
- Name = itemToInsert.Name,
- EmailAddress = itemToInsert.EmailAddress,
- HireDate = itemToInsert.HireDate,
- HasChildren = itemToInsert.HasChildren,
- DirectReports = itemToInsert.DirectReports
- };
- return await Task.FromResult(insertedItem);
- }
-
- async Task ServiceMimicUpdate(Employee itemToUpdate)
- {
- // in this example, we just populate the fields, you project may use
- // something else or generate the updated item differently
- Employee updatedItem = new Employee()
- {
- Id = itemToUpdate.Id,
- Name = itemToUpdate.Name,
- EmailAddress = itemToUpdate.EmailAddress,
- HireDate = itemToUpdate.HireDate,
- HasChildren = itemToUpdate.HasChildren,
- DirectReports = itemToUpdate.DirectReports
- };
- return await Task.FromResult(updatedItem);
- }
-
- async Task ServiceMimicDelete(Employee itemToDelete)
- {
- return await Task.FromResult(true);//always successful
- }
-
-
// sample visualization of the results
MarkupString logger;
void AppendToLog(string commandName, TreeListCommandEventArgs args)
@@ -275,11 +172,13 @@ Editing is cancelled for the first record.
logger = new MarkupString(logger + currAction);
}
+
// sample model
public class Employee
{
public int Id { get; set; }
+
public string Name { get; set; }
public string EmailAddress { get; set; }
public DateTime HireDate { get; set; }
@@ -301,65 +200,152 @@ Editing is cancelled for the first record.
}
// data generation
- // used in this example for data generation and assigning an ID to newly inserted items
- public int LastId { get; set; } = 1;
+
+ async Task GetTreeListData()
+ {
+ Data = await MyService.Read();
+ }
protected override async Task OnInitializedAsync()
{
- Data = await GetTreeListData();
+ await GetTreeListData();
}
- async Task> GetTreeListData()
+ // 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
{
- List data = new List();
+ private static List _data { get; set; } = new List();
+ // used in this example for data generation and retrieval for CUD operations on the current view-model data
+ private static int LastId { get; set; } = 1;
- for (int i = 1; i < 15; i++)
+ public static async Task Create(Employee itemToInsert, Employee parentItem)
{
- Employee root = new Employee
- {
- Id = LastId,
- Name = $"root: {i}",
- EmailAddress = $"{i}@example.com",
- HireDate = DateTime.Now.AddYears(-i),
- DirectReports = new List(),
- HasChildren = true
- };
- data.Add(root);
- LastId++;
-
- for (int j = 1; j < 4; j++)
+ InsertItemRecursive(_data, itemToInsert, parentItem);
+ }
+
+ public static async Task> Read()
+ {
+ if (_data.Count < 1)
{
- int currId = LastId;
- Employee firstLevelChild = new Employee
- {
- Id = currId,
- Name = $"first level child {j} of {i}",
- EmailAddress = $"{currId}@example.com",
- HireDate = DateTime.Now.AddDays(-currId),
- DirectReports = new List(),
- HasChildren = true
- };
- root.DirectReports.Add(firstLevelChild);
- LastId++;
-
- for (int k = 1; k < 3; k++)
+ for (int i = 1; i < 15; i++)
{
- int nestedId = LastId;
- firstLevelChild.DirectReports.Add(new Employee
+ Employee root = new Employee
{
Id = LastId,
- Name = $"second level child {k} of {j} and {i}",
- EmailAddress = $"{nestedId}@example.com",
- HireDate = DateTime.Now.AddMinutes(-nestedId)
- }); ;
+ Name = $"root: {i}",
+ EmailAddress = $"{i}@example.com",
+ HireDate = DateTime.Now.AddYears(-i),
+ DirectReports = new List(),
+ HasChildren = true
+ };
+ _data.Add(root);
LastId++;
+
+ for (int j = 1; j < 4; j++)
+ {
+ int currId = LastId;
+ Employee firstLevelChild = new Employee
+ {
+ Id = currId,
+ Name = $"first level child {j} of {i}",
+ EmailAddress = $"{currId}@example.com",
+ HireDate = DateTime.Now.AddDays(-currId),
+ DirectReports = new List(),
+ HasChildren = true
+ };
+ root.DirectReports.Add(firstLevelChild);
+ LastId++;
+
+ for (int k = 1; k < 3; k++)
+ {
+ int nestedId = LastId;
+ firstLevelChild.DirectReports.Add(new Employee
+ {
+ Id = LastId,
+ Name = $"second level child {k} of {j} and {i}",
+ EmailAddress = $"{nestedId}@example.com",
+ HireDate = DateTime.Now.AddMinutes(-nestedId)
+ }); ;
+ LastId++;
+ }
+ }
+ }
+
+ _data[0].Name += " (non-editable, see OnEdit)";
+ }
+
+ return await Task.FromResult(_data);
+ }
+
+ public static async Task Update(Employee itemToUpdate)
+ {
+ UpdateItemRecursive(_data, itemToUpdate);
+ }
+
+ public static async Task Delete(Employee itemToDelete)
+ {
+ RemoveChildRecursive(_data, itemToDelete);
+ }
+
+ // sample helper methods for handling the view-model data hierarchy
+ static void UpdateItemRecursive(List items, Employee itemToUpdate)
+ {
+ for (int i = 0; i < items.Count; i++)
+ {
+ if (items[i].Id.Equals(itemToUpdate.Id))
+ {
+ items[i] = itemToUpdate;
+ return;
+ }
+
+ if (items[i].DirectReports?.Count > 0)
+ {
+ UpdateItemRecursive(items[i].DirectReports, itemToUpdate);
+ }
+ }
+ }
+
+ static void RemoveChildRecursive(List items, Employee item)
+ {
+ for (int i = 0; i < items.Count(); i++)
+ {
+ if (item.Equals(items[i]))
+ {
+ items.Remove(item);
+
+ return;
+ }
+ else if (items[i].DirectReports?.Count > 0)
+ {
+ RemoveChildRecursive(items[i].DirectReports, item);
+
+ if (items[i].DirectReports.Count == 0)
+ {
+ items[i].HasChildren = false;
+ }
}
}
}
- data[0].Name += " (non-editable, see OnEdit)";
+ static void InsertItemRecursive(List Data, Employee insertedItem, Employee parentItem)
+ {
+ insertedItem.Id = LastId++;
+ if (parentItem != null)
+ {
+ parentItem.HasChildren = true;
+ if (parentItem.DirectReports == null)
+ {
+ parentItem.DirectReports = new List();
+ }
- return await Task.FromResult(data);
+ parentItem.DirectReports.Insert(0, insertedItem);
+ }
+ else
+ {
+ Data.Insert(0, insertedItem);
+ }
+ }
}
}
````
@@ -370,12 +356,11 @@ There are a few considerations to keep in mind with the CUD operations of the tr
* It is up to the data access logic to save the data once it is changed in the data collection. The example above showcases when that happens and adds some code to provide a visual indication of the change. In a real application, the code for handling data updates may be entirely different.
-* The CRUD event handlers must be `async Task` and **not** `async void`. A Task can be properly awaited and allows working with services and contexts. When the method returns `void`, the execution of the context operations is not actually awaited, and you may get errors from the context (such as "Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application" or "A second operation started on this context before a previous operation completed. This is usually caused by different threads using the same instance of DbContext").
+* The CRUD event handlers must be `async Task` and **not** `async void`. A Task can be properly awaited and allows working with services and contexts, and lets the treelist update after the actual data source operations complete.
-* The treelist uses `Activator.CreateInstance();` to generate a new item when an Insert action is invoked, so the Model should have a Parameterless constructor defined.
+ * When the method returns `void`, the execution of the context operations is not actually awaited, and you may get errors from the context (such as "Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application" or "A second operation started on this context before a previous operation completed. This is usually caused by different threads using the same instance of DbContext"). The treelist may also re-render before the actual data update happens and you may not see the result.
-
+* The treelist uses `Activator.CreateInstance();` to generate a new item when an Insert action is invoked, so the Model should have a Parameterless constructor defined. A workaround might be [invoking Insert through the treelist state]({%slug treelist-state%}#initiate-editing-or-inserting-of-an-item) and creating the object with your own code.
## See Also
diff --git a/components/treelist/editing/popup.md b/components/treelist/editing/popup.md
index 391e188c25..15bab0fe9c 100644
--- a/components/treelist/editing/popup.md
+++ b/components/treelist/editing/popup.md
@@ -58,6 +58,7 @@ Editing is cancelled for the first record.
+
@code {
public List Data { get; set; }
@@ -67,21 +68,22 @@ Editing is cancelled for the first record.
var item = args.Item as Employee;
// perform actual data source operations here through your service
- Employee updatedItem = await ServiceMimicUpdate(item);
+ await MyService.Update(item);
// update the local view-model data with the service data
- UpdateItemRecursive(Data, updatedItem);
+ await GetTreeListData();
}
async Task CreateItem(TreeListCommandEventArgs args)
{
- var argsItem = args.Item as Employee;
+ var item = args.Item as Employee;
+ var parentItem = args.ParentItem as Employee;
- // perform actual data source operation here through your service
- Employee insertedItem = await ServiceMimicInsert(argsItem);
+ // perform actual data source operations here through your service
+ await MyService.Create(item, parentItem);
// update the local view-model data with the service data
- InsertItemRecursive(Data, insertedItem, args);
+ await GetTreeListData();
}
async Task DeleteItem(TreeListCommandEventArgs args)
@@ -89,73 +91,10 @@ Editing is cancelled for the first record.
var item = args.Item as Employee;
// perform actual data source operations here through your service
- bool isDeleted = await ServiceMimicDelete(item);
-
- if (isDeleted)
- {
- // update the local view-model data
- RemoveChildRecursive(Data, item);
- }
- }
-
- // sample helper methods for handling the view-model data hierarchy
- void InsertItemRecursive(List Data, Employee insertedItem, TreeListCommandEventArgs args)
- {
- if (args.ParentItem != null)
- {
- var parent = (Employee)args.ParentItem;
-
- parent.HasChildren = true;
- if (parent.DirectReports == null)
- {
- parent.DirectReports = new List();
- }
+ await MyService.Delete(item);
- parent.DirectReports.Insert(0, insertedItem);
- }
- else
- {
- Data.Insert(0, insertedItem);
- }
- }
-
- void UpdateItemRecursive(List items, Employee itemToUpdate)
- {
- for (int i = 0; i < items.Count; i++)
- {
- if (items[i].Id.Equals(itemToUpdate.Id))
- {
- items[i] = itemToUpdate;
- return;
- }
-
- if (items[i].DirectReports?.Count > 0)
- {
- UpdateItemRecursive(items[i].DirectReports, itemToUpdate);
- }
- }
- }
-
- void RemoveChildRecursive(List items, Employee item)
- {
- for (int i = 0; i < items.Count(); i++)
- {
- if (item.Equals(items[i]))
- {
- items.Remove(item);
-
- return;
- }
- else if (items[i].DirectReports?.Count > 0)
- {
- RemoveChildRecursive(items[i].DirectReports, item);
-
- if (items[i].DirectReports.Count == 0)
- {
- items[i].HasChildren = false;
- }
- }
- }
+ // update the local view-model data with the service data
+ await GetTreeListData();
}
// OnEdit handler
@@ -180,49 +119,6 @@ Editing is cancelled for the first record.
}
- // the following three methods mimic an actual data service that handles the actual data source
- // you can see about implement error and exception handling, determining suitable return types as per your needs
-
- async Task ServiceMimicInsert(Employee itemToInsert)
- {
- // in this example, we just populate the fields, you project may use
- // something else or generate the updated item differently, we use "new" here
- Employee insertedItem = new Employee()
- {
- // the service assigns an ID, in this sample we use only the view-model data for simplicity,
- // you should use the actual data and set the properties as necessary (e.g., generate nested fields data and so on)
- Id = LastId++,
- Name = itemToInsert.Name,
- EmailAddress = itemToInsert.EmailAddress,
- HireDate = itemToInsert.HireDate,
- HasChildren = itemToInsert.HasChildren,
- DirectReports = itemToInsert.DirectReports
- };
- return await Task.FromResult(insertedItem);
- }
-
- async Task ServiceMimicUpdate(Employee itemToUpdate)
- {
- // in this example, we just populate the fields, you project may use
- // something else or generate the updated item differently
- Employee updatedItem = new Employee()
- {
- Id = itemToUpdate.Id,
- Name = itemToUpdate.Name,
- EmailAddress = itemToUpdate.EmailAddress,
- HireDate = itemToUpdate.HireDate,
- HasChildren = itemToUpdate.HasChildren,
- DirectReports = itemToUpdate.DirectReports
- };
- return await Task.FromResult(updatedItem);
- }
-
- async Task ServiceMimicDelete(Employee itemToDelete)
- {
- return await Task.FromResult(true);//always successful
- }
-
-
// sample model
public class Employee
@@ -252,65 +148,152 @@ Editing is cancelled for the first record.
}
// data generation
- // used in this example for data generation and assigning an ID to newly inserted items
- public int LastId { get; set; } = 1;
+
+ async Task GetTreeListData()
+ {
+ Data = await MyService.Read();
+ }
protected override async Task OnInitializedAsync()
{
- Data = await GetTreeListData();
+ await GetTreeListData();
}
- async Task> GetTreeListData()
+ // 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
{
- List data = new List();
+ private static List _data { get; set; } = new List();
+ // used in this example for data generation and retrieval for CUD operations on the current view-model data
+ private static int LastId { get; set; } = 1;
- for (int i = 1; i < 15; i++)
+ public static async Task Create(Employee itemToInsert, Employee parentItem)
{
- Employee root = new Employee
- {
- Id = LastId,
- Name = $"root: {i}",
- EmailAddress = $"{i}@example.com",
- HireDate = DateTime.Now.AddYears(-i),
- DirectReports = new List(),
- HasChildren = true
- };
- data.Add(root);
- LastId++;
-
- for (int j = 1; j < 4; j++)
+ InsertItemRecursive(_data, itemToInsert, parentItem);
+ }
+
+ public static async Task> Read()
+ {
+ if (_data.Count < 1)
{
- int currId = LastId;
- Employee firstLevelChild = new Employee
- {
- Id = currId,
- Name = $"first level child {j} of {i}",
- EmailAddress = $"{currId}@example.com",
- HireDate = DateTime.Now.AddDays(-currId),
- DirectReports = new List(),
- HasChildren = true
- };
- root.DirectReports.Add(firstLevelChild);
- LastId++;
-
- for (int k = 1; k < 3; k++)
+ for (int i = 1; i < 15; i++)
{
- int nestedId = LastId;
- firstLevelChild.DirectReports.Add(new Employee
+ Employee root = new Employee
{
Id = LastId,
- Name = $"second level child {k} of {j} and {i}",
- EmailAddress = $"{nestedId}@example.com",
- HireDate = DateTime.Now.AddMinutes(-nestedId)
- }); ;
+ Name = $"root: {i}",
+ EmailAddress = $"{i}@example.com",
+ HireDate = DateTime.Now.AddYears(-i),
+ DirectReports = new List(),
+ HasChildren = true
+ };
+ _data.Add(root);
LastId++;
+
+ for (int j = 1; j < 4; j++)
+ {
+ int currId = LastId;
+ Employee firstLevelChild = new Employee
+ {
+ Id = currId,
+ Name = $"first level child {j} of {i}",
+ EmailAddress = $"{currId}@example.com",
+ HireDate = DateTime.Now.AddDays(-currId),
+ DirectReports = new List(),
+ HasChildren = true
+ };
+ root.DirectReports.Add(firstLevelChild);
+ LastId++;
+
+ for (int k = 1; k < 3; k++)
+ {
+ int nestedId = LastId;
+ firstLevelChild.DirectReports.Add(new Employee
+ {
+ Id = LastId,
+ Name = $"second level child {k} of {j} and {i}",
+ EmailAddress = $"{nestedId}@example.com",
+ HireDate = DateTime.Now.AddMinutes(-nestedId)
+ }); ;
+ LastId++;
+ }
+ }
+ }
+
+ _data[0].Name += " (non-editable, see OnEdit)";
+ }
+
+ return await Task.FromResult(_data);
+ }
+
+ public static async Task Update(Employee itemToUpdate)
+ {
+ UpdateItemRecursive(_data, itemToUpdate);
+ }
+
+ public static async Task Delete(Employee itemToDelete)
+ {
+ RemoveChildRecursive(_data, itemToDelete);
+ }
+
+ // sample helper methods for handling the view-model data hierarchy
+ static void UpdateItemRecursive(List items, Employee itemToUpdate)
+ {
+ for (int i = 0; i < items.Count; i++)
+ {
+ if (items[i].Id.Equals(itemToUpdate.Id))
+ {
+ items[i] = itemToUpdate;
+ return;
+ }
+
+ if (items[i].DirectReports?.Count > 0)
+ {
+ UpdateItemRecursive(items[i].DirectReports, itemToUpdate);
}
}
}
- data[0].Name += " (non-editable, see OnEdit)";
+ static void RemoveChildRecursive(List items, Employee item)
+ {
+ for (int i = 0; i < items.Count(); i++)
+ {
+ if (item.Equals(items[i]))
+ {
+ items.Remove(item);
+
+ return;
+ }
+ else if (items[i].DirectReports?.Count > 0)
+ {
+ RemoveChildRecursive(items[i].DirectReports, item);
- return await Task.FromResult(data);
+ if (items[i].DirectReports.Count == 0)
+ {
+ items[i].HasChildren = false;
+ }
+ }
+ }
+ }
+
+ static void InsertItemRecursive(List Data, Employee insertedItem, Employee parentItem)
+ {
+ insertedItem.Id = LastId++;
+ if (parentItem != null)
+ {
+ parentItem.HasChildren = true;
+ if (parentItem.DirectReports == null)
+ {
+ parentItem.DirectReports = new List();
+ }
+
+ parentItem.DirectReports.Insert(0, insertedItem);
+ }
+ else
+ {
+ Data.Insert(0, insertedItem);
+ }
+ }
}
}
````
diff --git a/components/treelist/state.md b/components/treelist/state.md
index e509d86ae9..9b87620b6e 100644
--- a/components/treelist/state.md
+++ b/components/treelist/state.md
@@ -662,6 +662,7 @@ In addition to that, you can also use the `EditItem`, `OriginalEditItem`, `Inser
@code {
+ public List Data { get; set; }
TelerikTreeList TreeListRef { get; set; } = new TelerikTreeList();
async Task EnterEditMode()
@@ -688,48 +689,8 @@ In addition to that, you can also use the `EditItem`, `OriginalEditItem`, `Inser
await TreeListRef.SetState(state);
}
- public List Data { get; set; }
-
- // Sample CUD operations for the local data
- async Task UpdateItem(TreeListCommandEventArgs args)
- {
- var item = args.Item as Employee;
-
- // perform actual data source operations here through your service
- Employee updatedItem = await ServiceMimicUpdate(item);
-
- // update the local view-model data with the service data
- UpdateItemRecursive(Data, updatedItem);
- }
-
- async Task CreateItem(TreeListCommandEventArgs args)
- {
- var argsItem = args.Item as Employee;
-
- // perform actual data source operation here through your service
- Employee insertedItem = await ServiceMimicInsert(argsItem);
-
- // update the local view-model data with the service data
- InsertItemRecursive(Data, insertedItem, args);
- }
-
- async Task DeleteItem(TreeListCommandEventArgs args)
- {
- var item = args.Item as Employee;
-
- // perform actual data source operations here through your service
- bool isDeleted = await ServiceMimicDelete(item);
-
- if (isDeleted)
- {
- // update the local view-model data
- RemoveChildRecursive(Data, item);
- }
- }
-
-
- // sample helper methods for handling the view-model data hierarchy
- private Employee FindItemRecursive(List items, int id)
+ // sample helper method for handling the view-model data hierarchy
+ Employee FindItemRecursive(List items, int id)
{
foreach (var item in items)
{
@@ -752,108 +713,42 @@ In addition to that, you can also use the `EditItem`, `OriginalEditItem`, `Inser
return null;
}
- void InsertItemRecursive(List Data, Employee insertedItem, TreeListCommandEventArgs args)
+ // Sample CUD operations for the local data
+ async Task UpdateItem(TreeListCommandEventArgs args)
{
- if (args.ParentItem != null)
- {
- var parent = (Employee)args.ParentItem;
-
- parent.HasChildren = true;
- if (parent.DirectReports == null)
- {
- parent.DirectReports = new List();
- }
-
- parent.DirectReports.Insert(0, insertedItem);
- }
- else
- {
- Data.Insert(0, insertedItem);
- }
- }
+ var item = args.Item as Employee;
- void UpdateItemRecursive(List items, Employee itemToUpdate)
- {
- for (int i = 0; i < items.Count; i++)
- {
- if (items[i].Id.Equals(itemToUpdate.Id))
- {
- items[i] = itemToUpdate;
- return;
- }
+ // perform actual data source operations here through your service
+ await MyService.Update(item);
- if (items[i].DirectReports?.Count > 0)
- {
- UpdateItemRecursive(items[i].DirectReports, itemToUpdate);
- }
- }
+ // update the local view-model data with the service data
+ await GetTreeListData();
}
- void RemoveChildRecursive(List items, Employee item)
+ async Task CreateItem(TreeListCommandEventArgs args)
{
- for (int i = 0; i < items.Count(); i++)
- {
- if (item.Equals(items[i]))
- {
- items.Remove(item);
+ var item = args.Item as Employee;
+ var parentItem = args.ParentItem as Employee;
- return;
- }
- else if (items[i].DirectReports?.Count > 0)
- {
- RemoveChildRecursive(items[i].DirectReports, item);
+ // perform actual data source operations here through your service
+ await MyService.Create(item, parentItem);
- if (items[i].DirectReports.Count == 0)
- {
- items[i].HasChildren = false;
- }
- }
- }
+ // update the local view-model data with the service data
+ await GetTreeListData();
}
-
- // the following three methods mimic an actual data service that handles the actual data source
- // you can see about implement error and exception handling, determining suitable return types as per your needs
-
- async Task ServiceMimicInsert(Employee itemToInsert)
+ async Task DeleteItem(TreeListCommandEventArgs args)
{
- // in this example, we just populate the fields, you project may use
- // something else or generate the updated item differently, we use "new" here
- Employee insertedItem = new Employee()
- {
- // the service assigns an ID, in this sample we use only the view-model data for simplicity,
- // you should use the actual data and set the properties as necessary (e.g., generate nested fields data and so on)
- Id = LastId++,
- Name = itemToInsert.Name,
- EmailAddress = itemToInsert.EmailAddress,
- HireDate = itemToInsert.HireDate,
- HasChildren = itemToInsert.HasChildren,
- DirectReports = itemToInsert.DirectReports
- };
- return await Task.FromResult(insertedItem);
- }
+ var item = args.Item as Employee;
- async Task ServiceMimicUpdate(Employee itemToUpdate)
- {
- // in this example, we just populate the fields, you project may use
- // something else or generate the updated item differently
- Employee updatedItem = new Employee()
- {
- Id = itemToUpdate.Id,
- Name = itemToUpdate.Name,
- EmailAddress = itemToUpdate.EmailAddress,
- HireDate = itemToUpdate.HireDate,
- HasChildren = itemToUpdate.HasChildren,
- DirectReports = itemToUpdate.DirectReports
- };
- return await Task.FromResult(updatedItem);
- }
+ // perform actual data source operations here through your service
+ await MyService.Delete(item);
- async Task ServiceMimicDelete(Employee itemToDelete)
- {
- return await Task.FromResult(true);//always successful
+ // update the local view-model data with the service data
+ await GetTreeListData();
}
+
// sample model
public class Employee
@@ -908,63 +803,150 @@ In addition to that, you can also use the `EditItem`, `OriginalEditItem`, `Inser
}
// data generation
- // used in this example for data generation and assigning an ID to newly inserted items
- public int LastId { get; set; } = 1;
+
+ async Task GetTreeListData()
+ {
+ Data = await MyService.Read();
+ }
protected override async Task OnInitializedAsync()
{
- Data = await GetTreeListData();
+ await GetTreeListData();
}
- async Task> GetTreeListData()
+ // 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
{
- List data = new List();
+ private static List _data { get; set; } = new List();
+ // used in this example for data generation and retrieval for CUD operations on the current view-model data
+ private static int LastId { get; set; } = 1;
- for (int i = 1; i < 15; i++)
+ public static async Task Create(Employee itemToInsert, Employee parentItem)
{
- Employee root = new Employee
+ InsertItemRecursive(_data, itemToInsert, parentItem);
+ }
+
+ public static async Task> Read()
+ {
+ if (_data.Count < 1)
{
- Id = LastId,
- Name = $"root: {i}",
- EmailAddress = $"{i}@example.com",
- HireDate = DateTime.Now.AddYears(-i),
- DirectReports = new List(),
- HasChildren = true
- };
- data.Add(root);
- LastId++;
+ for (int i = 1; i < 15; i++)
+ {
+ Employee root = new Employee
+ {
+ Id = LastId,
+ Name = $"root: {i}",
+ EmailAddress = $"{i}@example.com",
+ HireDate = DateTime.Now.AddYears(-i),
+ DirectReports = new List(),
+ HasChildren = true
+ };
+ _data.Add(root);
+ LastId++;
- for (int j = 1; j < 4; j++)
+ for (int j = 1; j < 4; j++)
+ {
+ int currId = LastId;
+ Employee firstLevelChild = new Employee
+ {
+ Id = currId,
+ Name = $"first level child {j} of {i}",
+ EmailAddress = $"{currId}@example.com",
+ HireDate = DateTime.Now.AddDays(-currId),
+ DirectReports = new List(),
+ HasChildren = true
+ };
+ root.DirectReports.Add(firstLevelChild);
+ LastId++;
+
+ for (int k = 1; k < 3; k++)
+ {
+ int nestedId = LastId;
+ firstLevelChild.DirectReports.Add(new Employee
+ {
+ Id = LastId,
+ Name = $"second level child {k} of {j} and {i}",
+ EmailAddress = $"{nestedId}@example.com",
+ HireDate = DateTime.Now.AddMinutes(-nestedId)
+ }); ;
+ LastId++;
+ }
+ }
+ }
+ }
+
+ return await Task.FromResult(_data);
+ }
+
+ public static async Task Update(Employee itemToUpdate)
+ {
+ UpdateItemRecursive(_data, itemToUpdate);
+ }
+
+ public static async Task Delete(Employee itemToDelete)
+ {
+ RemoveChildRecursive(_data, itemToDelete);
+ }
+
+ // sample helper methods for handling the view-model data hierarchy
+ static void UpdateItemRecursive(List items, Employee itemToUpdate)
+ {
+ for (int i = 0; i < items.Count; i++)
{
- int currId = LastId;
- Employee firstLevelChild = new Employee
+ if (items[i].Id.Equals(itemToUpdate.Id))
{
- Id = currId,
- Name = $"first level child {j} of {i}",
- EmailAddress = $"{currId}@example.com",
- HireDate = DateTime.Now.AddDays(-currId),
- DirectReports = new List