LWC에서 Form 만들어보기

ahncheer·2024년 8월 27일
0

LWC & LWR

목록 보기
52/52

기능 정리

  • 필수 값인 경우 class를 사용해 빨간색 *을 추가하기 (is-req class를 추가)
  • 단순 필수 값 확인의 경우 반복해서 체크할 수 있도록 하기 (let reqField =[] 사용)
  • 이메일, 전화번호의 형식에 맞지 않는 경우 정규식을 사용해 확인하고, 다른 알림메세지를 띄우기
  • 저장 기능은 구현할 수 없으니, 모든 값이 잘 작성되었다면 console.log로 값을 확인할 수 있도록 하기

코드 짜기

1. html

<template>
    <div class="cpContactus">
        <lightning-spinner alternative-text="Loading" size="large" lwc:if={isLoading}></lightning-spinner>

        <h3 class="page-title">Contact us</h3>
        <div class="msg-form"> 
            <h3 class="sub-title"> Message</h3>
            <div>
                <!-- Category -->
                <div class="form-con is-req half-con">
                    <label for="category">Category</label>
                    <select name="category">
                        <option value="" disabled selected>--선택--</option>
                        <template for:each={cateList} for:item="item" for:index="index">
                            <option key={item.id} value={item.value}>{item.label}</option>
                        </template>
                    </select>
                </div>

                <!-- 제목 -->
                <div class="form-con is-req">
                    <label for="title">제목</label>
                    <input type="text" name="title" placeholder="제목을 입력해주세요." />
                </div>

                <!-- 문의내용 -->
                <div class="form-con is-req">
                    <label for="story">문의 내용</label>
                    <textarea name="story" rows="5" cols="33" placeholder="문의내용을 입력해주세요."></textarea>
                </div>
            </div>
        </div>

        <div class="user-form"> 
            <h3 class="sub-title">User Info</h3>
            <div>
                <!-- 이름 -->
                <div class="form-con is-req">
                    <label for="name">이름</label>
                    <input type="text" name="name" placeholder="이름을 입력해주세요." />
                </div>

                <!-- 이메일 -->
                <div class="form-con is-req">
                    <label for="email">이메일</label>
                    <input type="text" name="email" placeholder="이메일을 입력해주세요." />
                </div>

                <!-- 전화번호 -->
                <div class="form-con is-req">
                    <label for="tel">전화번호</label>
                    <input type="text" name="tel" placeholder="전화번호을 입력해주세요." />
                </div>

            </div>
        </div>

        <div class="agree-form"> 
            <h3 class="sub-title">개인정보 수집 동의</h3>
            <div>
                <div class="agree-txt">
                    개인정보 수집 동의 관련 내용이 들어갑니다.
                </div>
                <div class="form-con is-req">
                    <input type="checkbox" name="agree" />
                    <label for="agree">개인정보 수집에 동의합니다.</label>
                </div>
            </div>
        </div>
        <div class="btn-area"> 
            <button onclick={clickSubmit}>제출</button>
        </div>

        <div class="custom-modal-wrap" lwc:if={isModalOpen}>
            <div class="dimmed-bg"></div>
            <div class="modal-wrap"> 
                <p>{alertTxt}</p>
                <button onclick={closeModal}>확인</button>
            </div>
        </div>

    </div>
</template>a

2. js

import { LightningElement, track } from 'lwc';
export default class CpContactus extends LightningElement {
    @track cateList = [
        { label: '사이트', value: 'sites' },
        { label: '제품', value: 'products' },
    ];
    @track isLoading = false;
    @track alertTxt = '';
    @track isValidation = false;
    @track isModalOpen = false;

    clickSubmit() {
        console.log('clickSubmit');
        let data = {};
        let reqField = ['category', 'title', 'story', 'name', 'email', 'tel', 'agree'];
        reqField.forEach((el, index) => {
            let val = '';
            if(el == 'agree') {
                val = this.template.querySelector(`input[name="${el}"]`);
                data[el] = val.checked;
            }else{
                if(el == 'category') {
                    val = this.template.querySelector(`select[name="${el}"]`);
                }else if(el == 'story') {
                    val = this.template.querySelector(`textarea[name="${el}"]`);
                }else{
                    val = this.template.querySelector(`input[name="${el}"]`);
                }
                data[el] = val.value;
            }
        });
        console.log('data : ', JSON.parse(JSON.stringify(data)));
        this.validationCheck(data);
    }

    validationCheck(data) {
        let checkTxt = '';

        let checkReqTxt = '필수 값을 확인해 주세요.';
        let checkEmailTxt = '이메일 형식을 확인해주세요.';
        let checkTelTxt = '전화번호 형식을 확인해주세요.';
        let checkAgreeTxt = '개인정보 수집에 동의해주세요.';
        let checkField = {email : true, tel : true, agree : true, all : true};


        Object.keys(data).forEach((el) => {
            let val = data[el];

            if(el == 'email') {
                let emailRegex = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/i;
                if(!this.checkIsFilled(val)) {
                    checkField.all = false;
                }else if(!emailRegex.test(val)) {
                    checkField.email = false;
                }

            }else if(el == 'tel') {
                let telRegex = /^[0-9]*$/;
                if(!this.checkIsFilled(val)) {
                    checkField.all = false;
                }else if(!telRegex.test(val)) {
                    checkField.tel = false;
                }
            }else if(el == 'agree') {
                if(val == false) {
                    checkField.agree = false;
                }
            }else{
                if(!this.checkIsFilled(val)){
                    checkField.all = false;
                }

            }
        });
        console.log('checkField : ', JSON.parse(JSON.stringify(checkField)));

        if(checkField.email && checkField.tel && checkField.agree && checkField.all){
            this.isLoading = true;
            setTimeout(() => {
                this.isLoading = false;
                this.alertTxt = '문의 내용이 등록되었습니다.';
                this.isValidation = true;
                this.isModalOpen = true;
            }, 2000);
        }else{
            if(!checkField.all){
                checkTxt = checkReqTxt;
            }else if(!checkField.email){
                checkTxt = checkEmailTxt;
            }else if(!checkField.tel){
                checkTxt = checkTelTxt;
            }else if(!checkField.agree){
                checkTxt = checkAgreeTxt;
            }
            // alert(checkTxt);

            this.alertTxt = checkTxt;
            this.isValidation = false;
            this.isModalOpen = true;
        }
    }
    checkIsFilled(val) {
        let isFilled = (val != '' && val != undefined && val != 'undefined' && val.length > 0 && val.length != 0);
        return isFilled;
    }
    closeModal(){
        this.isModalOpen = false;
        this.alertTxt = '';
        console.log('this.isValidation : ', this.isValidation);

        if(this.isValidation == true){
            window.location.href = window.location.origin + basePathName;
        }
    }

}

3. css

.cpContactus{
	max-width: 1080px;
	margin: 0 auto;
}
.page-title{
	font-size: 24px;
    font-weight: bold;
    padding: 20px 0;
}
.agree-form, .user-form{
	margin-top: 60px;
}
.form-con {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

h3.sub-title {
    margin-bottom: 8px;
    font-size: 20px;
    font-weight: bold;
}

.form-con + .form-con {
    margin-top: 16px;
}

.agree-form .form-con {
    flex-direction: row;
}

.agree-txt {
    background-color: #f4f4f4;
    padding: 16px;
    margin-bottom: 16px;
    max-height: 150px;
    overflow-y: auto;
}

input[type="text"], textarea, select, option {
    padding: 8px;
    border: 1px solid #ddd;
    border-radius: 5px;
}

.is-req label {
    position: relative;
}

.is-req label:after {
    position: absolute;
    content: '*';
    color: red;
    margin-left: 3px;
    margin-top: -3px;
}

/* button */
.btn-area {
    text-align: center;
    margin-top: 60px;
}

.btn-area button {
    padding: 10px 20px;
    border: 0;
    border-radius: 10px;
    background-color: #333;
    color: #fff;
    font-size: 16px;
}

/* custom Alert */
.custom-modal-wrap {
    position: fixed;
    top: -25vh;
    left: -25vw;
    width: 150vw;
    height: 150vh;
    z-index: 9999;
    display: flex;
    align-items: center;
    justify-content: center;
}

.dimmed-bg {
    background-color: rgb(0 0 0 / 15%);
    width: 100%;
    height: 100%;
    position: absolute;
    top: 0;
    left: 0;
    z-index: -1;
}

.modal-wrap {
    background-color: #fff;
    width: 250px;
    height: 150px;
    padding: 20px;
    border-radius: 10px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 20px;
}

.modal-wrap p {
    font-size: 16px;
    text-align: center;
}

.modal-wrap button {
    width: 60%;
    margin: 0 auto;
    padding: 7px 10px;
    border: 0;
    border-radius: 10px;
    background-color: #333;
    color: #fff;
    font-size: 14px;
}

화면 확인

이메일 형식이 틀린 경우 이메일 형식 확인 알림이 뜸

필수값을 모두 입력하고 형식에 맞는 경우, 등록 완료 안내가 뜸 (실제로 등록되진 않고 console로 찍어두기)

profile
개인 공부 기록용.

0개의 댓글