Bootstrap validation 기능 사용법 및 Svelte에 적용하기

Bootstrap 을 이용해서 웹사이트를 만드는 편인데, 거기서 제공하는 validation 기능을 사용하고 있다. 그대로 Svelte 에서 사용할 수 있으면 좋겠지만, 그게 그렇게 되질 않았다. SvelteKit 을 사용하여 각페이지들을 Route 하기위해 페이지를 컴포넌트처럼 나누어 개발하고 합치기 때문인데, 알아보는 시간은 꽤나 오래걸렸지만 그래도 비슷하게 구현을 했다.

기본적인 html, js 파일 기능설명

우선 svelte 를 이용하지 않은 bootstrap validation 사용방법을 먼저 설명한다. 아래의 소스를 가지고 간략하게 설명해보려한다.

<body>
    <form class="row g-3 needs-validation" novalidate>
        <input type="text" class="form-control" value="Mark" required>
        <div class="valid-feedback">
            Looks good!
        </div>
        <div class="invalid-feedback">
            Please Input a username.
        </div>
    </form>
    <script src="validation.js"></script>
</body>

1. form 태그에 needs-validation 클래스 선언

우선 html 에서는 입력필수여부 체크하려는 form 태그에만 needs-validation 클래스를 선언해놓는다. 참고로 form 태그안에 novalidate 를 꼭 선언해야한다. 브라우저에서 폼데이터(form data)를 서버로 제출할 때 해당 데이터의 유효성을 검사하는데, 이 기능을 제거해야만 bootstrap 에서 제공하는 css/js 기능을 이용한 필수체크 효과를 사용할 수 있기 때문이다.

2. 필수체크를 원한다면 required 입력

input, select, textarea 등 입력 태그중 필수 입력 체크할 대상에만 required 키워드를 입력한다.

3. 결과 메시지를 선언한다.

부가적으로 체크결과에 대한 메시지를 각각 선언 가능하니, valid-feedback에는 성공메시지를, invalid-feedback 에는 오류메시지를 선언하면 된다.

4. body 내에 아래 js 파일을 선언한다.

필수 입력란으로 셋팅했는데, 빈값으로 submit 거래가 일어난다면, 그건 유효하지 않은 거래이니 거래가 일어나지 않도록 막아야 한다. 그 기능을 bootstrap 에서는 아래 소스로 제공하고 있다. 해당 소스를 valdation.js 라고 명명하고, 그 파일을 html body 태그안에서 연결만 해주면 끝이다.

// validation.js
(() => {
  'use strict'

  const forms = document.querySelectorAll('.needs-validation')

  // Loop over them and prevent submission
  Array.from(forms).forEach(form => {
    form.addEventListener('submit', event => {
      if (!form.checkValidity()) {
        event.preventDefault()
        event.stopPropagation()
      }

      form.classList.add('was-validated')
    }, false)
  })
})()

Bootstrap Validation 기능을 Svelte에서 적용하기

위에서 정의한 html 파일과 큰 변화는 없고, on:submit={checkForm} 만 추가되었다. onsubmit 이벤트를 사용할때, svelte 에서는 on:submit 와 같이 다르게 구사해야 한다. 안에 들어가 있는 checkForm 은 function 이름인데, onsubmit 이벤트에 checkForm 이란 함수를 바인딩 하는 것이다. 그리고 submit 이벤트가 일어난 form 에서만 필수체크를 하도록 기존에 있던 불필요한 Array 기능은 제거하였다. event 객체 안에는 다양한 정보들이 있기 때문에 조금 더 공부가 필요할 듯 하다.

<script>
    function checkForm(event){
        const form = event.target;
        if (!form.checkValidity()) {
            event.preventDefault();
            event.stopPropagation();
        }
        form.classList.add('was-validated');
    }
</script>
<div class="col-6">
    <form class="row g-3 needs-validation" on:submit={checkForm} novalidate>
        <input type="text" class="form-control" value="Mark" required>
        <div class="valid-feedback">
            Looks good!
        </div>
        <div class="invalid-feedback">
            Please Input a username.
        </div>
        <button class="btn btn-primary" type="submit">submit</button>
    </form>
</div>

checkForm 를 그러면 모든 svelte 페이지마다 정의를 해야하나? 아니다. lib 안에서 따로 정의하고, 그걸 필요한 svelte 페이지마다 import 해서 사용하는 방식으로 바꾸면 된다. 아래와 같이 2개의 파일로 나누어 필요한 곳에서만 선언해서 사용하면 된다.

// $lib/checkForm.js 파일
export default function(event){

    const form = event.target;

    if (!form.checkValidity()) {
        event.preventDefault();
        event.stopPropagation();
    }

    form.classList.add('was-validated');
}
<!-- form.svelte 파일 -->
<script>
    import checkForm from '$lib/checkForm.js'
</script>
<div class="col-6">
    <form class="row g-3 needs-validation" on:submit={checkForm} novalidate>
        <input type="text" class="form-control" value="Mark" required>
        <div class="valid-feedback">
            Looks good!
        </div>
        <div class="invalid-feedback">
            Please Input a username.
        </div>
        <button class="btn btn-primary" type="submit">submit</button>
    </form>
</div>

더 보면 좋을 글들