[] Validation 페이지 생성

This commit is contained in:
김선규 2024-10-08 11:01:04 +09:00
parent 4781a17b00
commit 22a9ed4531
25 changed files with 346 additions and 7 deletions

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GitToolBoxProjectSettings">
<option name="commitMessageIssueKeyValidationOverride">
<BoolValueOverride>
<option name="enabled" value="true" />
</BoolValueOverride>
</option>
<option name="commitMessageValidationEnabledOverride">
<BoolValueOverride>
<option name="enabled" value="true" />
</BoolValueOverride>
</option>
</component>
</project>

View File

@ -0,0 +1,21 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="HtmlUnknownTag" enabled="true" level="WARNING" enabled_by_default="true">
<option name="myValues">
<value>
<list size="7">
<item index="0" class="java.lang.String" itemvalue="nobr" />
<item index="1" class="java.lang.String" itemvalue="noembed" />
<item index="2" class="java.lang.String" itemvalue="comment" />
<item index="3" class="java.lang.String" itemvalue="noscript" />
<item index="4" class="java.lang.String" itemvalue="embed" />
<item index="5" class="java.lang.String" itemvalue="script" />
<item index="6" class="java.lang.String" itemvalue="validation-message" />
</list>
</value>
</option>
<option name="myCustomValuesEnabled" value="true" />
</inspection_tool>
</profile>
</component>

View File

@ -1,3 +1,5 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AComponentBase_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F0691f2c61b694470b2385ca13b1109b2ddc00_003Ffb_003F9d185c09_003FComponentBase_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ATask_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F35f3a54f5acb408a3e219b2de039f1a39557b7e4515f11238cba07b60c0ce_003FTask_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AThrowHelper_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F6780d13016c376c4491c5618b257d84da7eacf747ed2719783e775546b79b_003FThrowHelper_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AThrowHelper_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F6780d13016c376c4491c5618b257d84da7eacf747ed2719783e775546b79b_003FThrowHelper_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AValidationMessage_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fac3bd96e7bc584b5bed1f3fd84642ddcbc2756291a45fc2079313a609c56b6cc_003FValidationMessage_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>

View File

@ -14,4 +14,10 @@
<PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.1.0" />
</ItemGroup>
<ItemGroup>
<Compile Update="Components\Pages\ValidationPage\Validation.razor.cs">
<DependentUpon>Validation.razor</DependentUpon>
</Compile>
</ItemGroup>
</Project>

View File

@ -31,5 +31,11 @@
<span class="oi oi-list-rich" aria-hidden="true"></span> Todo
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="validation">
<span class="oi oi-list-rich" aria-hidden="true"></span> Validation
</NavLink>
</div>
</nav>
</div>

View File

@ -0,0 +1,17 @@
using System.ComponentModel.DataAnnotations;
namespace BlazorApp.Components.Pages.ValidationPage;
public class LoginModel
{
[Required(ErrorMessage = "ID는 필수 입력사항입니다.")]
public string Id {get; set;}
[Required(ErrorMessage = "비밀번호는 필수 입력사항입니다.")]
public string Pw {get; set;}
[Required(ErrorMessage = "이메일 설정은 필수 입력사항입니다.")]
[EmailAddress(ErrorMessage = "이메일 설정이 올바르지 않습니다.")]
public string Email {get; set;}
}

View File

@ -0,0 +1,55 @@
@page "/validation"
@rendermode InteractiveServer
<h3>Validation</h3>
<EditForm EditContext="@editContext" OnValidSubmit="HandleValidSubmit">
<DataAnnotationsValidator/>
@* <ValidationSummary/> *@
<div class="form-group">
<label>Username:</label>
<InputText @bind-Value="login.Id" @oninput="HandlerInputChange" @onblur="HandlerInputChange"/>
@if (isIdValid)
{
<p class="success-message">Username is valid!</p>
}
else
{
<ValidationMessage For="@(() => login.Id)" style="padding-left: 10px"/>
}
</div>
<div class="form-group">
<label>PW:</label>
<InputText @bind-Value="login.Pw" @oninput="HandlerInputChange" @onblur="HandlerInputChange"/>
@if (isPwValid)
{
<p class="success-message">pass is valid!</p>
}
else
{
<ValidationMessage For="@(() => login.Pw)" style="padding-left: 10px"/>
}
</div>
<div class="form-group">
<label>Email:</label>
<InputText @bind-Value="login.Email" @oninput="HandlerInputChange" @onblur="HandlerInputChange"/>
@if (isEmailValid)
{
<p class="success-message">Email is valid!</p>
}
else
{
<ValidationMessage For="@(() => login.Email)" style="padding-left: 10px"/>
}
</div>
<div class="form-group form-actions">
<button type="submit">Submit</button>
</div>
</EditForm>
<hr>

View File

@ -0,0 +1,50 @@
using System.ComponentModel.DataAnnotations;
using BlazorApp.Components.Pages.ValidationPage;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
namespace BlazorApp.Components.Pages.ValidationPage;
public partial class Validation : ComponentBase
{
private LoginModel login = new LoginModel();
private EditContext editContext;
private bool isIdValid = false;
private bool isPwValid = false;
private bool isEmailValid = false;
protected override void OnInitialized()
{
Console.WriteLine("Oninitialized");
editContext = new EditContext(login);
Console.WriteLine(isPwValid);
// editContext.OnFieldChanged += HandleFieldChanged;
}
private void HandlerInputChange()
{
Console.WriteLine("HandlerInputChange");
// 유효성 검사가 발생했다? = true
tryCheckValidate();
StateHasChanged();
}
private void tryCheckValidate()
{
editContext.Validate();
Console.WriteLine($"{isIdValid}, {isPwValid}, {isEmailValid}");
Console.WriteLine(editContext.GetValidationMessages(() => login.Id).Any());
Console.WriteLine(editContext.GetValidationMessages(() => login.Pw).Any());
Console.WriteLine(editContext.GetValidationMessages(() => login.Email).Any());
isIdValid = !editContext.GetValidationMessages(() => login.Id).Any();
isPwValid = !editContext.GetValidationMessages(() => login.Pw).Any();
isEmailValid = !editContext.GetValidationMessages(() => login.Email).Any();
}
private void HandleValidSubmit()
{
// 유효성 검사에 성공했을 때의 처리
Console.WriteLine("Form submitted successfully");
}
}

View File

@ -0,0 +1,34 @@
.form-group {
display: flex;
flex-direction: row;
align-items: center;
margin-bottom: 10px;
}
.form-group label {
width: 100px;
text-align: right;
margin-right: 10px;
padding-right: 4px;
}
.form-group input {
flex: 1;
width: 500px;
}
.form-actions {
display: flex;
justify-content: center;
margin-top: 10px;
}
.success-message {
color: blue;
font-weight: bold;
/*text-align: left;*/
height: 100%;
margin-left: 10px;
}

View File

@ -13,7 +13,7 @@ using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("BlazorApp")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+e554ba22b3f3cdd8bd0ce3cb5c93355b57e25261")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+4781a17b00b8e21414f02e947102acf72c5c6178")]
[assembly: System.Reflection.AssemblyProductAttribute("BlazorApp")]
[assembly: System.Reflection.AssemblyTitleAttribute("BlazorApp")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]

View File

@ -1 +1 @@
0d413a05c0600afacbfef2252958fa268ae4252fd91bc9042018004bdc1236f9
d6262563cb144b1b24689bcb852f66331e78b742afea34cc7526f77806d8fefb

View File

@ -57,3 +57,7 @@ build_metadata.AdditionalFiles.CssScope = b-zswk0q6kaa
[/Users/seankim/1.Program/Project(ASP)/BlazorApp/BlazorApp/Components/Pages/TodoPage/Todo.razor]
build_metadata.AdditionalFiles.TargetPath = Q29tcG9uZW50cy9QYWdlcy9Ub2RvUGFnZS9Ub2RvLnJhem9y
build_metadata.AdditionalFiles.CssScope = b-n64y2ur3f8
[/Users/seankim/1.Program/Project(ASP)/BlazorApp/BlazorApp/Components/Pages/ValidationPage/Validation.razor]
build_metadata.AdditionalFiles.TargetPath = Q29tcG9uZW50cy9QYWdlcy9WYWxpZGF0aW9uUGFnZS9WYWxpZGF0aW9uLnJhem9y
build_metadata.AdditionalFiles.CssScope = b-z8q1q1jnjv

View File

@ -1 +1 @@
3607e99c4bc36a4bae6dfb6e1b940004d67160fc7f174a874004b6f7cde31fdd
50edfd86d0e1da31fa31883ae82e1f3520bbce7f4aabb52fd74698655be3fe0f

View File

@ -32,3 +32,4 @@
/Users/seankim/1.Program/Project(ASP)/BlazorApp/BlazorApp/obj/Debug/net8.0/BlazorApp.genruntimeconfig.cache
/Users/seankim/1.Program/Project(ASP)/BlazorApp/BlazorApp/obj/Debug/net8.0/ref/BlazorApp.dll
/Users/seankim/1.Program/Project(ASP)/BlazorApp/BlazorApp/obj/Debug/net8.0/scopedcss/Components/Pages/TodoPage/Todo.razor.rz.scp.css
/Users/seankim/1.Program/Project(ASP)/BlazorApp/BlazorApp/obj/Debug/net8.0/scopedcss/Components/Pages/ValidationPage/Validation.razor.rz.scp.css

View File

@ -0,0 +1,34 @@
.form-group[b-z8q1q1jnjv] {
display: flex;
flex-direction: row;
align-items: center;
margin-bottom: 10px;
}
.form-group label[b-z8q1q1jnjv] {
width: 100px;
text-align: right;
margin-right: 10px;
padding-right: 4px;
}
.form-group input[b-z8q1q1jnjv] {
flex: 1;
width: 500px;
}
.form-actions[b-z8q1q1jnjv] {
display: flex;
justify-content: center;
margin-top: 10px;
}
.success-message[b-z8q1q1jnjv] {
color: blue;
font-weight: bold;
/*text-align: left;*/
height: 100%;
margin-left: 10px;
}

View File

@ -208,7 +208,6 @@ main[b-fekawvbbds] {
}
/* _content/BlazorApp/Components/Pages/TodoPage/Todo.razor.rz.scp.css */
/* todo 용 CSS */
.list-item[b-n64y2ur3f8] {
display: flex;
align-items: center;
@ -258,3 +257,38 @@ main[b-fekawvbbds] {
.small-button:active[b-n64y2ur3f8] {
background-color: #dddddd;
}
/* _content/BlazorApp/Components/Pages/ValidationPage/Validation.razor.rz.scp.css */
.form-group[b-z8q1q1jnjv] {
display: flex;
flex-direction: row;
align-items: center;
margin-bottom: 10px;
}
.form-group label[b-z8q1q1jnjv] {
width: 100px;
text-align: right;
margin-right: 10px;
padding-right: 4px;
}
.form-group input[b-z8q1q1jnjv] {
flex: 1;
width: 500px;
}
.form-actions[b-z8q1q1jnjv] {
display: flex;
justify-content: center;
margin-top: 10px;
}
.success-message[b-z8q1q1jnjv] {
color: blue;
font-weight: bold;
/*text-align: left;*/
height: 100%;
margin-left: 10px;
}

View File

@ -208,7 +208,6 @@ main[b-fekawvbbds] {
}
/* _content/BlazorApp/Components/Pages/TodoPage/Todo.razor.rz.scp.css */
/* todo 용 CSS */
.list-item[b-n64y2ur3f8] {
display: flex;
align-items: center;
@ -258,3 +257,38 @@ main[b-fekawvbbds] {
.small-button:active[b-n64y2ur3f8] {
background-color: #dddddd;
}
/* _content/BlazorApp/Components/Pages/ValidationPage/Validation.razor.rz.scp.css */
.form-group[b-z8q1q1jnjv] {
display: flex;
flex-direction: row;
align-items: center;
margin-bottom: 10px;
}
.form-group label[b-z8q1q1jnjv] {
width: 100px;
text-align: right;
margin-right: 10px;
padding-right: 4px;
}
.form-group input[b-z8q1q1jnjv] {
flex: 1;
width: 500px;
}
.form-actions[b-z8q1q1jnjv] {
display: flex;
justify-content: center;
margin-top: 10px;
}
.success-message[b-z8q1q1jnjv] {
color: blue;
font-weight: bold;
/*text-align: left;*/
height: 100%;
margin-left: 10px;
}

View File

@ -210,7 +210,7 @@ public class TodoItem
• 목표: Blazor의 기본적인 컴포넌트 구조와 데이터 바인딩을 학습
• 포인트:
• 컴포넌트 생성 및 렌더링
• 데이터 바인딩 (@bind)
• 데이터 바인딩 (bind)
• 이벤트 핸들링
• 설명: 사용자가 할 일을 입력하고, 목록에서 완료된 할 일을 삭제하는 간단한 애플리케이션

View File

@ -0,0 +1,26 @@
# 지식
## 1. 코드 비하인드 패턴
- .razor 파일과 .cs 파일을 분리해서 사용하는 방식
- A.razor <br>
├ A.razor.cs <br>
⎿ A.razor.css
### 역할
1. .razor 파일 : 주로 UI 마크업을 포함
2. .cs 파일 : 관련 로직을 포함 - @code 블록을 대신해 서로 연결 됨
## 2. EditForm
- Blazor 제공하는 Form Compornents.
- 데이터 바인딩, 유효성 검사, 폼 제출 처리에 사용
- 사용자 입력 수집하고, 입력 데이터 검증 후 서버나 클라이언트 제출하는 기능 제공
### 1. InputText
- @bind-Value 로 변수와 엮어주기
<br>
<선택사항>
- @oninput 은 입력시 수행할 이벤트 엮어주기
- @onblur 는 포커스 해제시 수행할 이벤트 엮어주기
## 3. Attribute
- 변수나 클래스, 메서드 위에 [ ]를 사용해 속성을 추가
- 코드에서 어떤 동작이나 정보를 제공하거나, 특정 조건에 따라 처리되는 방식을 지정할 수 있다.
- 이미 존재하는(Required, Range, Obsolte, 등) 속성들도 있지만, 사용자가 직접 정의해서 사용할 수 있다.
- 2의 EditForm과 엮으면 좋음