티스토리 뷰

폼 유효성 검사에 실패했을 때 어느 항목이 잘못됐는지 시각적으로 알려주는 방법이다. 부트스트랩 느낌의 경고 스타일을 직접 만들어 쓴다.

1. Laravel Custom Helper 만들기

if (!function_exists('hasError')) {

    function hasError($errName, $isMsg = false)
    {
        if ($errors = session('errors', new \Illuminate\Support\MessageBag())) {
            if ($isError = $errors->has($errName)) {
                 return $isMsg
                      ? $errors->first($errName, ':message')
                      : 'has-error';
            }
        }
    }
}

두 번째 인자로 동작이 갈린다. false면 CSS 클래스명을, true면 에러 메시지를 반환한다. 하나의 헬퍼로 클래스와 메시지를 모두 처리하려는 의도다.

헬퍼 파일 등록

헬퍼 함수를 만들었으면 오토로드에 등록해야 한다.

// composer.json
"autoload": {
    "files": [
        "app/Helpers/functions.php"
    ]
}
composer dump-autoload

2. CSS 처리

input.has-error {
    box-shadow: 0 0 5px rgba(255, 90, 90, 1);
    padding: 3px 0px 3px 3px;
    margin: 5px 1px 3px 0px;
    border: 1px solid rgba(255, 90, 90, 1);
}

textareaselect에도 적용하려면 선택자를 확장한다.

input.has-error,
textarea.has-error,
select.has-error {
    box-shadow: 0 0 5px rgba(255, 90, 90, 1);
    border: 1px solid rgba(255, 90, 90, 1);
}

3. 폼 HTML

<input class="{{ hasError('phone') }}" 
    type="text" 
    name="phone" 
    id="phone" value="{{ old('phone') }}">

old('phone')가 중요하다. 이게 없으면 검증 실패로 되돌아왔을 때 사용자가 입력했던 값이 전부 날아간다. 항목이 많은 폼에서는 치명적이다.

에러 메시지도 같이 표시

<input class="{{ hasError('phone') }}" type="text" name="phone" value="{{ old('phone') }}">

@if(hasError('phone'))
    <span class="error-text">{{ hasError('phone', true) }}</span>
@endif

Laravel 기본 기능으로도 된다

사실 헬퍼를 직접 만들지 않아도 Laravel이 제공하는 디렉티브가 있다.

<input class="@error('phone') has-error @enderror"
       type="text" name="phone" value="{{ old('phone') }}">

@error('phone')
    <span class="error-text">{{ $message }}</span>
@enderror

@error 디렉티브는 Laravel 5.8.13부터 들어왔다. 별도 헬퍼 없이 쓸 수 있고, 안에서 $message 변수를 바로 쓸 수 있다.

그래도 헬퍼를 만드는 게 나은 경우가 있다. 여러 프로젝트에서 동일한 클래스 규칙을 쓰거나, 반환할 클래스명이 프레임워크마다 다를 때(is-invalid vs has-error) 한 곳에서 관리할 수 있다.

접근성도 같이 챙기면 좋다

색상만으로 오류를 알리면 색각 이상이 있는 사용자는 인지하지 못한다. 텍스트 메시지를 반드시 함께 표시하고, 스크린 리더용 속성도 붙이는 게 좋다.

<input type="text" name="phone"
       class="@error('phone') has-error @enderror"
       aria-invalid="@error('phone')true@else false@enderror"
       aria-describedby="phone-error">

@error('phone')
    <span id="phone-error" role="alert">{{ $message }}</span>
@enderror

role="alert"가 있으면 스크린 리더가 에러 발생 시 즉시 읽어준다.

컴포넌트로 묶기

폼 항목이 많으면 매번 같은 코드를 반복하게 된다. 블레이드 컴포넌트로 만들면 훨씬 깔끔하다.

<!-- resources/views/components/input.blade.php -->
@props(['name', 'label', 'type' => 'text'])

<div class="form-group">
    <label for="{{ $name }}">{{ $label }}</label>
    <input type="{{ $type }}" name="{{ $name }}" id="{{ $name }}"
           value="{{ old($name) }}"
           class="@error($name) has-error @enderror">
    @error($name)
        <span class="error-text" role="alert">{{ $message }}</span>
    @enderror
</div>
<!-- 사용 -->
<x-input name="phone" label="휴대폰 번호" />
<x-input name="email" label="이메일" type="email" />

정리

  • 헬퍼로 has-error 클래스와 메시지를 함께 처리할 수 있다
  • old()를 빠뜨리면 사용자 입력이 전부 날아간다
  • Laravel 5.8.13+ 는 @error 디렉티브로 헬퍼 없이 가능
  • 색상만으로 알리지 말고 텍스트 메시지role="alert" 함께
  • 항목이 많으면 블레이드 컴포넌트로 묶는다
댓글


최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday