- bootstrap, jquery를 이용하여 모달폼 제어 기능 사용.
- ER CORE를 이용한 CRUD구현
- 클라이언트쪽 라이브러리 관리를 이용하여 라이브러리 다운로드 사용하기.
- EditForm을 이용하여 유효성 검사 사용.
클라이언트쪽 라이브러리를 사용 하여 라이브러리 다운받기.
{
"version": "1.0",
"defaultProvider": "cdnjs",
"libraries": [
{
"library": "jquery@3.4.1",
"files": [ "jquery.js" ],
"destination": "wwwroot/lib" //로컬에 저장할 파일경로
},
{
"provider": "jsdelivr",
"library": "bootstrap@4.4.1",
"files": [ "dist/js/bootstrap.js" ],
"destination": "wwwroot/lib" //로컬에 저장할 파일경로
}
]
}
using System.ComponentModel.DataAnnotations;
namespace ManufacturerApp.Model
{
public class Manufacturer
{
public int Id { get; set; }
[Required] //반드시 입력하도록 어노테이션 설정
public string name { get; set; }
[Required] //반드시 입력하도록 어노테이션 설정
public string ManufacturerCode { get; set; }
public string? Comment { get; set; } //null 허용
}
}
using ManufacturerApp.Model;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
namespace ManufacturerApp.Data
{
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<Manufacturer> Manufacturers { get; set; }
}
}
패키지 관리자 콘솔에서
1. add-migration "내용 기재. " //마이그레이션 업데이트
2. update-database //마이그레이션한 내용을 DB에 업데이트함.
- Er Core를 이용하기 위해 인터페이스 구현 및 CRUD 코드 구현.
namespace ManufacturerApp.Model
{
public interface IManufacturerRepository
{
public Task<Manufacturer> AddmanufacturerAsync(Manufacturer model);
public Task<List<Manufacturer>> GetManufacturersAsync();
public Task<Manufacturer> GetManufacturerAsync(int id);
public Task<Manufacturer> EditmanufacturerAsync(Manufacturer model);
public Task DeleteManufacturerAsync(int id);
}
}
using ManufacturerApp.Data;
using Microsoft.EntityFrameworkCore;
namespace ManufacturerApp.Model
{
public class ManufacturerRepository : IManufacturerRepository
{
private readonly ApplicationDbContext _dbContext;
public ManufacturerRepository(ApplicationDbContext dbContext) //생성자를 이용해 dbContext를 받아옴.
{
_dbContext = dbContext;
}
public async Task<Manufacturer> AddmanufacturerAsync(Manufacturer model)
{
await _dbContext.AddAsync(model);
await _dbContext.SaveChangesAsync();
return model;
}
public async Task DeleteManufacturerAsync(int id)
{
var manufacturer = await _dbContext.Manufacturers.FindAsync(id);
if (manufacturer != null)
{
_dbContext.Manufacturers.Remove(manufacturer);
await _dbContext.SaveChangesAsync();
}
}
public async Task<Manufacturer> EditmanufacturerAsync(Manufacturer model)
{
_dbContext.Entry(model).State = EntityState.Modified;
await _dbContext.SaveChangesAsync();
return model;
}
public async Task<Manufacturer> GetManufacturerAsync(int id)
{
return await _dbContext.Manufacturers.FindAsync(id);
}
public async Task<List<Manufacturer>> GetManufacturersAsync()
{
return await _dbContext.Manufacturers.ToListAsync();
}
}
}
- jquery를 이용해 모달 폼 close , show 구현.
- Layout.cshtml 혹은 Host.cshtml에서 javascript(모달 close, show) 구현
- 수정,등록을 같은 모달 component를 사용.
-Layout.cshtml
@using Microsoft.AspNetCore.Components.Web
@namespace ManufacturerApp.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<base href="~/" />
<link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" />
<link href="css/site.css" rel="stylesheet" />
<link href="ManufacturerApp.styles.css" rel="stylesheet" />
<component type="typeof(HeadOutlet)" render-mode="ServerPrerendered" />
</head>
<body>
@RenderBody()
<div id="blazor-error-ui">
<environment include="Staging,Production">
An error has occurred. This application may no longer respond until reloaded.
</environment>
<environment include="Development">
An unhandled exception has occurred. See browser dev tools for details.
</environment>
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>
<script src="_framework/blazor.server.js"></script>
<!--bootstrap, jquey 추가-->
<script src="/lib/jquery.js"></script>
<script src="/lib/dist/js/bootstrap.js"></script>
<!--jquery를 이용해 모달 팝업 및 close 구현.-->
<script>
function closeModal(modalId) {
$("#" + modalId).modal('hide');
}
function showModal(modalId) {
$("#" + modalId).modal('show');
}
</script>
</body>
</html>
- bootstrap 기능인 data-toggle="modal" data-target="#manufacturerEditDialog"을 사용해 id를 통해 modal창을 팝업 함.
@page "/Manufacturer/ManufacturerList"
@inject IManufacturerRepository manufacturerRepository
@inject IJSRuntime js
<h3>ManufacturerList</h3>
@if (Manufacturers == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Manufacturer Code</th>
<th>Comment</th>
</tr>
</thead>
<tbody>
@foreach (var manufacturer in Manufacturers)
{
<tr>
<td>@manufacturer.Id</td>
<td>@manufacturer.name</td>
<td>@manufacturer.ManufacturerCode</td>
<td>@manufacturer.Comment</td>
<td>
<input type="button" class="btn btn-primary" value="Edit"
@onclick="(() => EditBy(manufacturer))"
data-toggle="modal" data-target="#manufacturerEditDialog">
</td>
<td><input type="button" class="btn btn-danger" value="Delete"
@onclick="(() => DeleteBy(manufacturer))"
data-toggle="modal" data-target="#manufacturerDeleteDialog">
</td>
</tr>
}
</tbody>
</table>
<div>
<input type="button" @onclick="InsertBy" value="등록" class="btn btn-primary"
data-toggle="modal" data-target="#manufacturerEditDialog">
</div>
}
<ManufacturerDeleteDialog OnClick="btnDelete_Click"></ManufacturerDeleteDialog> <!--delete 모달 Component 실행-->
<ManufacturerEditDialog manufacturer="@manufacturer" EditOrInsert="EditOrInsert">
<renderFragment>
<b>수정</b>
<b>등록</b>
@renderTitle
</renderFragment>
</ManufacturerEditDialog>
@code {
List<Manufacturer> Manufacturers = null;
Manufacturer manufacturer = new Manufacturer();
string renderTitle = string.Empty;
Action UpdateOrInsert = null;
protected override async Task OnInitializedAsync()
{
Manufacturers = await manufacturerRepository.GetManufacturersAsync();
}
protected async Task btnDelete_Click()
{
await manufacturerRepository.DeleteManufacturerAsync(manufacturer.Id);
await js.InvokeVoidAsync("closeModal", "manufacturerDeleteDialog"); //_Layout.cshtml에서 생성한 펑션 closemodal 호출. 모달 폼 close
Manufacturers = await manufacturerRepository.GetManufacturersAsync(); //DB 에서 List 갱신.
manufacturer = new Manufacturer();
}
protected void DeleteBy(Manufacturer manufacturer)
{
this.manufacturer = manufacturer;
}
protected void InsertBy()
{
renderTitle = "<b>등록</b>";
manufacturer = new Manufacturer();
}
protected void EditBy(Manufacturer manufacturer)
{
renderTitle = "<b>수정</b>";
this.manufacturer = manufacturer;
}
protected async void EditOrInsert()
{
// manufacturer = new Manufacturer();
Manufacturers = await manufacturerRepository.GetManufacturersAsync();
await InvokeAsync(StateHasChanged);
}
}
- List페이지에서 삭제하는 메소드를 이벤트로 받아 yes 버튼을 클릭시 해당 메소드를 이벤트 형식으로 실행.
<div class="modal" tabindex="-1" role="dialog" id="manufacturerDeleteDialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Delete Confirm</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<p>정말로 삭제하시겠습니까?</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" @onclick="OnClick">Yes</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
</div>
</div>
</div>
</div>
@code
{
[Parameter]
public EventCallback<MouseEventArgs> OnClick { get; set; }
public void Editmanufacturer()
{
}
}
- List페이지에서 Manufacturer모델을 받아 해당 데이터들을 폼에 출력.
수정일 경우 기존값이 있지만 등록일 경우 빈값으로 출력.- EditForm(blazor Component)를 이용 하여 유효성 검사
DataAnnotationsValidator : 유효성 검사 테그
ValidationSummary : 유효성 위반시 모든 메시지 출력.
<ValidationMessage For="(() => manufacturer.name)"></ValidationMessage>
: 해당 컬럼에 대한 유효성 위반 메시지 출력- Submit 버튼을 눌렀을때 유효성 검사 후 유효성 통과시 등록 혹은 수정이 실행되며
모달폼 close는 앞에서 만든 javascript를 호출하여 modal폼의 id를 넘겨 close 시킴.- renderFragment는 부모측에서 구현한 ui를 그대로 자식 컴포넌트에서 출력시킴.
아래 사진을 보면<b>
테그가 적용 된것과 적용 되지 않은것을 볼 수 있음.
그 이유로 ui에서 직접 코디안 테그는 적용이 됬으나 @renderTitle변수를 사용해서 넘길 경우 string 타입으로 넘기기 때문에 테그 적용이 안된것을 확인 할 수 있음.
<renderFragment> <b>수정</b> <b>등록</b> @renderTitle </renderFragment>
@inject IJSRuntime js
@inject IManufacturerRepository manufacturerRepository
<div class="modal" tabindex="-1" role="dialog" id="manufacturerEditDialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">@renderFragment</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<EditForm Model="manufacturer" OnValidSubmit="submit_Click">
<DataAnnotationsValidator></DataAnnotationsValidator> <!--유효성검사.-->
<ValidationSummary></ValidationSummary> <!--유효성 위반 메시지 전체 출력-->
<input type="hidden" @bind-value=manufacturer.Id />
<div class="form-group">
<label for="name">이름</label>
<InputText id="name" class="form-control" @bind-Value="manufacturer.name"></InputText>
<ValidationMessage For="(() => manufacturer.name)"></ValidationMessage> <!--해당 컬럼에 대한 유효성 위반 메시지 출력-->
</div>
<div class="form-group">
<label for="code">코드</label>
<InputText id="code" class="form-control" @bind-Value="manufacturer.ManufacturerCode"></InputText>
<ValidationMessage For="(() => manufacturer.ManufacturerCode)"></ValidationMessage>
</div>
<div class="form-group">
<label for="comment">코멘트</label>
<InputText id="comment" class="form-control" @bind-Value="manufacturer.Comment"></InputText>
<ValidationMessage For="(() => manufacturer.Comment)"></ValidationMessage>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
</EditForm>
</div>
</div>
</div>
</div>
@code
{
[Parameter]
public Action EditOrInsert { get; set; }
[Parameter]
public Manufacturer manufacturer { get; set; }
[Parameter]
public RenderFragment renderFragment { get; set; } //RenderFragment 호출쪽에서 구현 ui 구현 테그도 같이 적용 가능.
protected async void submit_Click()
{
if (manufacturer.Id == 0) //등록
{
await manufacturerRepository.AddmanufacturerAsync(manufacturer);
}
else // 수정
{
await manufacturerRepository.EditmanufacturerAsync(manufacturer);
}
await js.InvokeVoidAsync("closeModal", "manufacturerEditDialog");
EditOrInsert(); //부모폼 상태값 업데이트
}
// protected void btnCancel_Click()
// {
// manufacturer = new Manufacturer();
// }
}
- 모델에서 유효성 강제로 적용 시켜준 필드에 한해 아래와 같이 위반시 메시지 출력 및 표시 됨.
- 이름 상단은 유효성 위반된 모든 메시지 출력.
- 각 필드 하단은 각필드에 해당하는 메시지만 출력.