Skip to content

Commit 8d0ba7e

Browse files
chore(form):added form validation (#99)
* chore(form):added form validation * Update form/remote-validation/readme.md Co-authored-by: Dimo Dimov <[email protected]> * Update form/remote-validation/readme.md Co-authored-by: Dimo Dimov <[email protected]> * Update form/remote-validation/readme.md Co-authored-by: Dimo Dimov <[email protected]> * Update form/remote-validation/readme.md Co-authored-by: Dimo Dimov <[email protected]> * Update form/remote-validation/readme.md Co-authored-by: Dimo Dimov <[email protected]> * chore(form):final readme file fixes Co-authored-by: Dimo Dimov <[email protected]>
1 parent a9a6275 commit 8d0ba7e

34 files changed

+1588
-0
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 16
4+
VisualStudioVersion = 16.0.31129.286
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WasmCustomValidation.Server", "WasmCustomValidation\Server\WasmCustomValidation.Server.csproj", "{1223DE2A-08B2-4319-9024-5690B18BFFAF}"
7+
EndProject
8+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WasmCustomValidation.Client", "WasmCustomValidation\Client\WasmCustomValidation.Client.csproj", "{F357039D-DD41-44AF-9B67-D4189BE10F84}"
9+
EndProject
10+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WasmCustomValidation.Shared", "WasmCustomValidation\Shared\WasmCustomValidation.Shared.csproj", "{F03A79AE-B35D-4830-8D4C-EC313F1C9284}"
11+
EndProject
12+
Global
13+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
14+
Debug|Any CPU = Debug|Any CPU
15+
Release|Any CPU = Release|Any CPU
16+
EndGlobalSection
17+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
18+
{1223DE2A-08B2-4319-9024-5690B18BFFAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19+
{1223DE2A-08B2-4319-9024-5690B18BFFAF}.Debug|Any CPU.Build.0 = Debug|Any CPU
20+
{1223DE2A-08B2-4319-9024-5690B18BFFAF}.Release|Any CPU.ActiveCfg = Release|Any CPU
21+
{1223DE2A-08B2-4319-9024-5690B18BFFAF}.Release|Any CPU.Build.0 = Release|Any CPU
22+
{F357039D-DD41-44AF-9B67-D4189BE10F84}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23+
{F357039D-DD41-44AF-9B67-D4189BE10F84}.Debug|Any CPU.Build.0 = Debug|Any CPU
24+
{F357039D-DD41-44AF-9B67-D4189BE10F84}.Release|Any CPU.ActiveCfg = Release|Any CPU
25+
{F357039D-DD41-44AF-9B67-D4189BE10F84}.Release|Any CPU.Build.0 = Release|Any CPU
26+
{F03A79AE-B35D-4830-8D4C-EC313F1C9284}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27+
{F03A79AE-B35D-4830-8D4C-EC313F1C9284}.Debug|Any CPU.Build.0 = Debug|Any CPU
28+
{F03A79AE-B35D-4830-8D4C-EC313F1C9284}.Release|Any CPU.ActiveCfg = Release|Any CPU
29+
{F03A79AE-B35D-4830-8D4C-EC313F1C9284}.Release|Any CPU.Build.0 = Release|Any CPU
30+
EndGlobalSection
31+
GlobalSection(SolutionProperties) = preSolution
32+
HideSolutionNode = FALSE
33+
EndGlobalSection
34+
GlobalSection(ExtensibilityGlobals) = postSolution
35+
SolutionGuid = {6F4EB78D-E923-4B93-8C9D-67FB2C401908}
36+
EndGlobalSection
37+
EndGlobal
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<Router AppAssembly="@typeof(Program).Assembly">
2+
<Found Context="routeData">
3+
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
4+
</Found>
5+
<NotFound>
6+
<LayoutView Layout="@typeof(MainLayout)">
7+
<p>Sorry, there's nothing at this address.</p>
8+
</LayoutView>
9+
</NotFound>
10+
</Router>
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
@page "/"
2+
3+
@using System.Net
4+
@using System.Net.Http.Json
5+
@using WasmCustomValidation.Shared
6+
@inject HttpClient Http
7+
8+
Try to fill all inputs except the "Description" when the "Classification" is set to Defense.
9+
<br />
10+
Try to submit with empty fields.
11+
<br/>
12+
This sample uses a Notification component to show the error message to supplement any data annotation validation.
13+
14+
<TelerikForm Model="@myModel" OnValidSubmit="@HandleValidSubmit">
15+
<FormValidation>
16+
<TelerikNotification @ref="@Notification"
17+
HorizontalPosition="@NotificationHorizontalPosition.Center"
18+
VerticalPosition="@NotificationVerticalPosition.Top"
19+
Class="big-notification">
20+
</TelerikNotification>
21+
<CustomValidation @ref="customValidation" />
22+
<ValidationSummary />
23+
</FormValidation>
24+
</TelerikForm>
25+
26+
@code {
27+
private bool disabled;
28+
private string message;
29+
private string messageStyles = "visibility:hidden";
30+
private CustomValidation customValidation;
31+
private MyModel myModel = new() {};
32+
33+
TelerikNotification Notification { get; set; }
34+
35+
void ShowErrorNotification(string message)
36+
{
37+
Notification.Show(new NotificationModel { CloseAfter = 0, Text = message, ThemeColor = Telerik.Blazor.ThemeColors.Error });
38+
}
39+
40+
private async Task HandleValidSubmit(EditContext editContext)
41+
{
42+
customValidation.ClearErrors();
43+
44+
try
45+
{
46+
var response = await Http.PostAsJsonAsync<MyModel>(
47+
"MyValidation", (MyModel)editContext.Model);
48+
49+
var errors = await response.Content
50+
.ReadFromJsonAsync<Dictionary<string, List<string>>>();
51+
52+
if (response.StatusCode == HttpStatusCode.BadRequest &&
53+
errors.Count() > 0)
54+
{
55+
customValidation.DisplayErrors(errors);
56+
57+
foreach (var error in errors)
58+
{
59+
foreach (var errorName in error.Value)
60+
{
61+
ShowErrorNotification(errorName);
62+
}
63+
}
64+
}
65+
else if (!response.IsSuccessStatusCode)
66+
{
67+
throw new HttpRequestException(
68+
$"Validation failed. Status Code: {response.StatusCode}");
69+
}
70+
else
71+
{
72+
disabled = true;
73+
messageStyles = "color:green";
74+
message = "The form has been processed.";
75+
}
76+
}
77+
catch (Exception ex)
78+
{
79+
disabled = true;
80+
messageStyles = "color:red";
81+
message = "There was an error processing the form.";
82+
}
83+
}
84+
}
85+
86+
<style>
87+
.big-notification .k-notification-container .k-notification-wrap {
88+
width: 330px;
89+
height: 80px;
90+
align-items: center;
91+
font-size: 26px;
92+
text-align: center;
93+
}
94+
95+
.big-notification .k-notification-container .k-notification-wrap .k-icon.k-i-error::before {
96+
font-size: 26px;
97+
}
98+
99+
.big-notification {
100+
z-index: 654321;
101+
}
102+
</style>
103+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
2+
using Microsoft.Extensions.DependencyInjection;
3+
using System;
4+
using System.Net.Http;
5+
using System.Threading.Tasks;
6+
7+
namespace WasmCustomValidation.Client
8+
{
9+
public class Program
10+
{
11+
public static async Task Main(string[] args)
12+
{
13+
var builder = WebAssemblyHostBuilder.CreateDefault(args);
14+
builder.RootComponents.Add<App>("#app");
15+
builder.Services.AddTransient(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
16+
17+
builder.Services.AddTelerikBlazor();
18+
19+
await builder.Build().RunAsync();
20+
}
21+
}
22+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"iisSettings": {
3+
"windowsAuthentication": false,
4+
"anonymousAuthentication": true,
5+
"iisExpress": {
6+
"applicationUrl": "http://localhost:55337/",
7+
"sslPort": 44377
8+
}
9+
},
10+
"profiles": {
11+
"IIS Express": {
12+
"commandName": "IISExpress",
13+
"launchBrowser": true,
14+
"environmentVariables": {
15+
"ASPNETCORE_ENVIRONMENT": "Development"
16+
}
17+
},
18+
"WasmCustomValidation.Client": {
19+
"commandName": "Project",
20+
"launchBrowser": true,
21+
"environmentVariables": {
22+
"ASPNETCORE_ENVIRONMENT": "Development"
23+
},
24+
"applicationUrl": "https://localhost:5001;http://localhost:5000"
25+
}
26+
}
27+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using Microsoft.AspNetCore.Components;
4+
using Microsoft.AspNetCore.Components.Forms;
5+
6+
namespace WasmCustomValidation.Shared
7+
{
8+
public class CustomValidation : ComponentBase
9+
{
10+
private ValidationMessageStore messageStore;
11+
12+
[CascadingParameter]
13+
private EditContext CurrentEditContext { get; set; }
14+
15+
protected override void OnInitialized()
16+
{
17+
if (CurrentEditContext == null)
18+
{
19+
throw new InvalidOperationException(
20+
$"{nameof(CustomValidation)} requires a cascading " +
21+
$"parameter of type {nameof(EditContext)}. " +
22+
$"For example, you can use {nameof(CustomValidation)} " +
23+
$"inside an {nameof(EditForm)}.");
24+
}
25+
26+
messageStore = new(CurrentEditContext);
27+
28+
CurrentEditContext.OnValidationRequested += (s, e) =>
29+
messageStore.Clear();
30+
CurrentEditContext.OnFieldChanged += (s, e) =>
31+
messageStore.Clear(e.FieldIdentifier);
32+
}
33+
34+
public void DisplayErrors(Dictionary<string, List<string>> errors)
35+
{
36+
foreach (var err in errors)
37+
{
38+
messageStore.Add(CurrentEditContext.Field(err.Key), err.Value);
39+
}
40+
41+
CurrentEditContext.NotifyValidationStateChanged();
42+
}
43+
44+
public void ClearErrors()
45+
{
46+
messageStore.Clear();
47+
CurrentEditContext.NotifyValidationStateChanged();
48+
}
49+
}
50+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
@layout TelerikLayout
2+
3+
@inherits LayoutComponentBase
4+
5+
<div class="sidebar">
6+
<NavMenu />
7+
</div>
8+
9+
<div class="main">
10+
<div class="top-row px-4">
11+
<a href="http://blazor.net" target="_blank" class="ml-md-auto">About</a>
12+
</div>
13+
14+
<div class="content px-4">
15+
@Body
16+
</div>
17+
</div>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<div class="top-row pl-4 navbar navbar-dark">
2+
<a class="navbar-brand" href="">WasmCustomValidation</a>
3+
<button class="navbar-toggler" @onclick="ToggleNavMenu">
4+
<span class="navbar-toggler-icon"></span>
5+
</button>
6+
</div>
7+
8+
<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
9+
<ul class="nav flex-column">
10+
<li class="nav-item px-3">
11+
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
12+
<span class="oi oi-home" aria-hidden="true"></span> Home
13+
</NavLink>
14+
</li>
15+
</ul>
16+
</div>
17+
18+
@code {
19+
bool collapseNavMenu = true;
20+
21+
string NavMenuCssClass => collapseNavMenu ? "collapse" : null;
22+
23+
void ToggleNavMenu()
24+
{
25+
collapseNavMenu = !collapseNavMenu;
26+
}
27+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@inherits LayoutComponentBase
2+
3+
<TelerikRootComponent>
4+
@Body
5+
</TelerikRootComponent>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
2+
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
3+
<PropertyGroup>
4+
<TargetFramework>net5.0</TargetFramework>
5+
</PropertyGroup>
6+
<ItemGroup>
7+
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="5.0.0" />
8+
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="5.0.6" />
9+
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="5.0.0" PrivateAssets="all" />
10+
<PackageReference Include="System.Net.Http.Json" Version="5.0.0" />
11+
<PackageReference Include="Telerik.UI.for.Blazor" Version="2.24.0" />
12+
</ItemGroup>
13+
<ItemGroup>
14+
<ProjectReference Include="..\Shared\WasmCustomValidation.Shared.csproj" />
15+
</ItemGroup>
16+
</Project>

0 commit comments

Comments
 (0)