Skip to content

Commit f04a215

Browse files
feat(listview): validation examples
1 parent c783d87 commit f04a215

31 files changed

+1758
-0
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 16
4+
VisualStudioVersion = 16.0.30517.126
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ValidationExamples", "ValidationExamples\ValidationExamples.csproj", "{55A2D6E3-4A97-474A-BF2E-3928D49F096D}"
7+
EndProject
8+
Global
9+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
10+
Debug|Any CPU = Debug|Any CPU
11+
Release|Any CPU = Release|Any CPU
12+
EndGlobalSection
13+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
14+
{55A2D6E3-4A97-474A-BF2E-3928D49F096D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15+
{55A2D6E3-4A97-474A-BF2E-3928D49F096D}.Debug|Any CPU.Build.0 = Debug|Any CPU
16+
{55A2D6E3-4A97-474A-BF2E-3928D49F096D}.Release|Any CPU.ActiveCfg = Release|Any CPU
17+
{55A2D6E3-4A97-474A-BF2E-3928D49F096D}.Release|Any CPU.Build.0 = Release|Any CPU
18+
EndGlobalSection
19+
GlobalSection(SolutionProperties) = preSolution
20+
HideSolutionNode = FALSE
21+
EndGlobalSection
22+
GlobalSection(ExtensibilityGlobals) = postSolution
23+
SolutionGuid = {00FC26FB-D1A7-4E68-990F-90EF5BD808F3}
24+
EndGlobalSection
25+
EndGlobal
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<Router AppAssembly="typeof(Program).Assembly">
2+
<Found Context="routeData">
3+
<RouteView RouteData="routeData" DefaultLayout="typeof(MainLayout)" />
4+
</Found>
5+
<NotFound>
6+
<h1>Page not found</h1>
7+
<p>Sorry, but there's nothing here!</p>
8+
</NotFound>
9+
</Router>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using System;
2+
3+
namespace ValidationExamples.Data
4+
{
5+
public class WeatherForecast
6+
{
7+
public DateTime Date { get; set; }
8+
9+
public int TemperatureC { get; set; }
10+
11+
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
12+
13+
public string Summary { get; set; }
14+
}
15+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using System;
2+
using System.Linq;
3+
using System.Threading.Tasks;
4+
5+
namespace ValidationExamples.Data
6+
{
7+
public class WeatherForecastService
8+
{
9+
private static readonly string[] Summaries = new[]
10+
{
11+
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
12+
};
13+
14+
public Task<WeatherForecast[]> GetForecastAsync(DateTime startDate)
15+
{
16+
var rng = new Random();
17+
return Task.FromResult(Enumerable.Range(1, 5).Select(index => new WeatherForecast
18+
{
19+
Date = startDate.AddDays(index),
20+
TemperatureC = rng.Next(-20, 55),
21+
Summary = Summaries[rng.Next(Summaries.Length)]
22+
}).ToArray());
23+
}
24+
}
25+
}
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
@page "/async"
2+
3+
<div class="alert alert-info">This example adds a dummy delay in the update/create operations to simulate an actual remote service (you can add your own, and remove that code). The addition compared to the basic example is the <code>isEditing</code> flag that determines whether to rehydrate the edit context when the delay in the EventCallback re-renders the listview and the templates. This lets you prevent re-initializing that context upon/after completing the data operation.</div>
4+
5+
@using System.ComponentModel.DataAnnotations
6+
7+
<TelerikListView Data="@ListViewData" Pageable="true"
8+
OnCreate="@CreateHandler" OnDelete="@DeleteHandler" OnUpdate="@UpdateHandler" OnCancel="@CancelHandler" OnEdit="@EditHandler">
9+
<EditTemplate>
10+
<div style="border: 1px solid green; margin: 10px; padding: 10px; display: inline-block;">
11+
@{
12+
currEditItem = context;
13+
if (isEditing && currEditContext == null)
14+
{
15+
currEditContext = new EditContext(currEditItem);
16+
}
17+
18+
if (currEditContext != null)
19+
{
20+
<EditForm EditContext="@currEditContext" Context="formContext">
21+
<DataAnnotationsValidator />
22+
<TelerikTextBox @bind-Value="@currEditItem.Name" Label="Name" />
23+
<ValidationMessage For="@(() => currEditItem.Name)"></ValidationMessage>
24+
25+
<br />
26+
<TelerikDropDownList Data="@Teams" @bind-Value="@currEditItem.Team" />
27+
28+
<ListViewCommandButton Command="Save" Icon="@IconName.Save">Save</ListViewCommandButton>
29+
<ListViewCommandButton Command="Cancel" Icon="@IconName.Cancel">Cancel</ListViewCommandButton>
30+
</EditForm>
31+
}
32+
}
33+
</div>
34+
</EditTemplate>
35+
<Template>
36+
<div style="border: 1px solid black; margin: 10px; padding: 10px; display: inline-block;">
37+
Employee: @context.Id <br />
38+
Name: @context.Name in team: @context.Team
39+
<ListViewCommandButton Command="Edit" Icon="@IconName.Edit">Edit</ListViewCommandButton>
40+
<ListViewCommandButton Command="Delete" Icon="@IconName.Delete">Delete</ListViewCommandButton>
41+
</div>
42+
</Template>
43+
<HeaderTemplate>
44+
<ListViewCommandButton Command="Add" Icon="@IconName.Plus">Add Employee</ListViewCommandButton>
45+
<p>In this sample, the first item will not open for editing because of the code in the OnEdit handler</p>
46+
</HeaderTemplate>
47+
</TelerikListView>
48+
49+
@code{
50+
Employee currEditItem { get; set; }
51+
EditContext currEditContext { get; set; }
52+
bool isEditing { get; set; }
53+
54+
void EditHandler()
55+
{
56+
isEditing = true;
57+
CleanUpValidation();
58+
}
59+
60+
async Task CreateHandler(ListViewCommandEventArgs e)
61+
{
62+
Employee insertedItem = e.Item as Employee;
63+
64+
65+
// lower the flag so we don't rehydrate the edit context - the EventCallback will re-render the ListView (including its templates) after it completes
66+
// you can flip it back to true as needed (e.g., if validation fails, to rehydrate the validation logic)
67+
isEditing = false;
68+
69+
// simulate a delay - be that server data operation, or server validation
70+
await Task.Delay(400);
71+
72+
// sample validation - you can extend it to get information back from the server/service
73+
if (!currEditContext.Validate())
74+
{
75+
// prevent the listview from going back in view mode
76+
e.IsCancelled = true;
77+
isEditing = true;
78+
return;
79+
}
80+
81+
// if you need remote validation (e.g., check for duplicates on the server)
82+
// add it here through your data service and cancel the event as well
83+
84+
// save actual data here through your service
85+
86+
// update the view-model, can use returned data from the remote service too
87+
insertedItem.Id = ListViewData.Count + 1;
88+
ListViewData.Insert(0, insertedItem);
89+
90+
CleanUpValidation();
91+
}
92+
93+
async Task DeleteHandler(ListViewCommandEventArgs e)
94+
{
95+
Employee deletedItem = e.Item as Employee;
96+
97+
ListViewData.Remove(deletedItem);
98+
99+
// save to the actual data source here as well
100+
}
101+
102+
async Task UpdateHandler(ListViewCommandEventArgs e)
103+
{
104+
Employee updatedItem = e.Item as Employee;
105+
106+
// lower the flag so we don't rehydrate the edit context - the EventCallback will re-render the ListView (including its templates) after it completes
107+
// you can flip it back to true as needed (e.g., if validation fails, to rehydrate the validation logic)
108+
isEditing = false;
109+
110+
// simulate a delay - be that server data operation, or server validation
111+
await Task.Delay(400);
112+
113+
// sample validation - you can extend it to get information back from the server/service
114+
if (!currEditContext.Validate())
115+
{
116+
// prevent the listview from going back in view mode
117+
e.IsCancelled = true;
118+
isEditing = true;
119+
return;
120+
}
121+
122+
// if you need remote validation (e.g., check for duplicates on the server)
123+
// add it here through your data service and cancel the event as well
124+
125+
// save actual data here through your service
126+
127+
// update the view-model, can use returned data from the remote service too
128+
int index = ListViewData.FindIndex(itm => itm.Id == updatedItem.Id);
129+
if (index > -1)
130+
{
131+
ListViewData[index] = updatedItem;
132+
}
133+
134+
CleanUpValidation();
135+
}
136+
137+
void CancelHandler(ListViewCommandEventArgs e)
138+
{
139+
isEditing = false;
140+
CleanUpValidation();
141+
}
142+
143+
void CleanUpValidation()
144+
{
145+
// clean up for next run
146+
currEditContext = null;
147+
currEditItem = null;
148+
}
149+
150+
// data and models follow
151+
152+
List<Employee> ListViewData { get; set; }
153+
154+
protected override void OnInitialized()
155+
{
156+
ListViewData = Enumerable.Range(1, 250).Select(x => new Employee
157+
{
158+
Id = x,
159+
Name = $"Name {x}",
160+
Team = Teams[x % Teams.Count]
161+
}).ToList();
162+
}
163+
164+
List<string> Teams = new List<string> { "Sales", "Dev", "Support" };
165+
166+
public class Employee
167+
{
168+
public int Id { get; set; }
169+
170+
[Required(ErrorMessage = "Enter a name")]
171+
public string Name { get; set; }
172+
173+
public string Team { get; set; }
174+
}
175+
}

0 commit comments

Comments
 (0)