[blazor] jquery, bootstrap 기본 기능을 이용한 CRUD 게시판 생성(EditForm)

코찔찔이·2023년 10월 11일
0

blazor강의 따라하기

목록 보기
23/23
  1. bootstrap, jquery를 이용하여 모달폼 제어 기능 사용.
  2. ER CORE를 이용한 CRUD구현
  3. 클라이언트쪽 라이브러리 관리를 이용하여 라이브러리 다운로드 사용하기.
  4. EditForm을 이용하여 유효성 검사 사용.

1. 클라이언트쪽 라이브러리 사용.

클라이언트쪽 라이브러리를 사용 하여 라이브러리 다운받기.

{
  "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" //로컬에 저장할 파일경로
    }

  ]
}


2. 모델생성

  • Manufacturer.cs 생성
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 허용
    }
}

3. DBContext에 생성한 모델 DbSet 만들고 마이그레이션 및 DBUpdate

  • ApplicationDbContext.cs
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에 업데이트함.

4. CRUD 구현을 위한 Repository 구현

  1. Er Core를 이용하기 위해 인터페이스 구현 및 CRUD 코드 구현.
  • IManufacturerRepository.cs(인터페이스)
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);
    }

}
  • ManufacturerRepository.cs(CRUD구현코드)
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();
        }
    }

}

5. 페이지 구현

  1. jquery를 이용해 모달 폼 close , show 구현.
  2. Layout.cshtml 혹은 Host.cshtml에서 javascript(모달 close, show) 구현
  3. 수정,등록을 같은 모달 component를 사용.

1. cshtml에서 모달 show ,close javascript 펑션 생성

-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>

2. List 페이지

  1. bootstrap 기능인 data-toggle="modal" data-target="#manufacturerEditDialog"을 사용해 id를 통해 modal창을 팝업 함.

  • ManufacturerList.razor
@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);
    }
}

3. delete 모달

  1. List페이지에서 삭제하는 메소드를 이벤트로 받아 yes 버튼을 클릭시 해당 메소드를 이벤트 형식으로 실행.
  1. 삭제전

  1. 삭제후

  • ManufacturerDeleteDialog.razor
<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">&times;</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()
    {

    }

}

4. 수정, 등록 모달폼 생성.

  1. List페이지에서 Manufacturer모델을 받아 해당 데이터들을 폼에 출력.
    수정일 경우 기존값이 있지만 등록일 경우 빈값으로 출력.
  2. EditForm(blazor Component)를 이용 하여 유효성 검사
    DataAnnotationsValidator : 유효성 검사 테그
    ValidationSummary : 유효성 위반시 모든 메시지 출력.
    <ValidationMessage For="(() => manufacturer.name)"></ValidationMessage> : 해당 컬럼에 대한 유효성 위반 메시지 출력
  3. Submit 버튼을 눌렀을때 유효성 검사 후 유효성 통과시 등록 혹은 수정이 실행되며
    모달폼 close는 앞에서 만든 javascript를 호출하여 modal폼의 id를 넘겨 close 시킴.
  4. 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">&times;</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();
    // }
}

5. 유효성 검사.

  1. 모델에서 유효성 강제로 적용 시켜준 필드에 한해 아래와 같이 위반시 메시지 출력 및 표시 됨.
  2. 이름 상단은 유효성 위반된 모든 메시지 출력.
  3. 각 필드 하단은 각필드에 해당하는 메시지만 출력.

0개의 댓글