그냥 폼검증말고 왜 틀렸는지 이런걸 알려주는 폼검증을 만들어보자!
js 라이브러리 등등 이런게 많지만 내입맛에 맞게 수정하기 편하기 위해서는 결국 직접 만드는것이 가장 좋겠다고 판단했다
https://codepen.io/trending
CodePen
An online code editor, learning environment, and community for front-end web development using HTML, CSS and JavaScript code snippets, projects, and web applications.
codepen.io
여기 사이트에서 적당한 예시를 찾아서 수정했는데 정확한 url을 다시 찾으려고하니 못찾겠다...
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
* {
box-sizing: border-box;
}
body {
background-color: blueviolet;
}
.title {
margin-bottom: 2rem;
}
.hidden {
display: none;
}
.icon {
width: 24px;
height: 24px;
position: absolute;
top: 32px;
right: 5px;
pointer-events: none;
z-index: 2;
&.icon-success {
fill: green;
}
&.icon-error {
fill: red;
}
}
.container {
max-width: 460px;
margin: 3rem auto;
padding: 3rem;
border: 1px solid #ddd;
border-radius: 0.25rem;
background-color: white;
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
}
.label {
font-weight: bold;
display: block;
color: #333;
margin-bottom: 0.25rem;
color: #2d3748;
}
.input {
appearance: none;
display: block;
width: 100%;
color: #2d3748;
border: 1px solid #cbd5e0;
line-height: 1.25;
background-color: white;
padding: 0.65rem 0.75rem;
border-radius: 0.25rem;
box-shadow: inset 0 2px 4px 0 rgba(0, 0, 0, 0.06);
&::placeholder {
color: #a0aec0;
}
&.input-error {
border: 1px solid red;
&:focus {
border: 1px solid red;
}
}
&:focus {
outline: none;
border: 1px solid #a0aec0;
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
background-clip: padding-box;
}
}
.input-group {
margin-bottom: 2rem;
position: relative;
}
.error-message {
font-size: 0.85rem;
color: red;
display: block;
}
.button {
background-color: blueviolet;
padding: 1rem 2rem;
border: none;
border-radius: 0.25rem;
color: white;
font-weight: bold;
display: block;
width: 100%;
text-align: center;
cursor: pointer;
&:hover {
filter: brightness(110%);
}
}
.promo {
color: white;
opacity: 0.75;
margin: 1rem auto;
max-width: 460px;
background: rgba(255, 255, 255, 0.2);
padding: 20px;
border-radius: 0.25rem;
a {
color: white;
}
}
</style>
</head>
<body>
<div class="container">
<h2 class="title">Create a new account</h2>
<form action="#" class="form">
<div class="input-group">
<label for="username" class="label">이름</label>
<input id="username" placeholder="webcrunch" type="text" class="input" name="username" formval_min="5" formval_max="15" />
<span class="error-message"></span>
<svg class="icon icon-success hidden" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd" />
</svg>
<svg class="icon icon-error hidden" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z" clip-rule="evenodd" />
</svg>
</div>
<div class="input-group">
<label for="username" class="label">셀렉트 박스</label>
<span class="error-message"></span>
<select name="selectBox0" id="selectBox0">
<option value="">선택x</option>
<option value="1">선택1</option>
<option value="2">선택2</option>
<option value="3">선택3</option>
<option value="4">선택4</option>
</select>
<svg class="icon icon-success hidden" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd" />
</svg>
<svg class="icon icon-error hidden" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z" clip-rule="evenodd" />
</svg>
</div>
<div class="input-group">
<label class="label">체크박스</label>
<span class="error-message"></span>
<label for="checkbox1" class="label">체크박스선택1</label>
<input id="checkbox1" name="checkbox00" type="checkbox" class="formValCheckBox" value="1" formval_min="1" formval_max="2" />
<label for="checkbox2" class="label">체크박스선택2</label>
<input id="checkbox2" name="checkbox00" type="checkbox" class="formValCheckBox" value="2" />
<label for="checkbox2-1" class="label">체크박스선택2.1</label>
<input id="checkbox2-1" name="checkbox00" type="checkbox" class="formValCheckBox" value="2.1" />
<svg class="icon icon-success hidden" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd" />
</svg>
<svg class="icon icon-error hidden" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z" clip-rule="evenodd" />
</svg>
</div>
<div class="input-group">
<label class="label">체크박스</label>
<span class="error-message"></span>
<div>
<label for="checkbox3" class="label">체크박스선택3</label>
<input id="checkbox3" name="checkbox01" type="checkbox" class="" value="3" />
</div>
<div>
<label for="checkbox4" class="label">체크박스선택4</label>
<input id="checkbox4" name="checkbox01" type="checkbox" class="" value="4" />
</div>
<svg class="icon icon-success hidden" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd" />
</svg>
<svg class="icon icon-error hidden" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z" clip-rule="evenodd" />
</svg>
</div>
<div class="input-group">
<label for="email" class="label">Email</label>
<input id="email" type="email" class="input" name="email" autocomplete placeholder="andy@web-crunch.com" />
<span class="error-message"></span>
<svg class="icon icon-success hidden" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd" />
</svg>
<svg class="icon icon-error hidden" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z" clip-rule="evenodd" />
</svg>
</div>
<div class="input-group">
<label for="password" class="label">Password</label>
<input id="password" type="password" class="input" name="password" />
<span class="error-message"></span>
<svg class="icon icon-success hidden" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd" />
</svg>
<svg class="icon icon-error hidden" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z" clip-rule="evenodd" />
</svg>
</div>
<div class="input-group">
<label for="password_confirmation" class="label">Password Confirmation</label>
<input id="password_confirmation" type="password" class="input" name="password_confirmation" />
<span class="error-message"></span>
<svg class="icon icon-success hidden" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd" />
</svg>
<svg class="icon icon-error hidden" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z" clip-rule="evenodd" />
</svg>
</div>
<input type="submit" class="button" value="Create account" />
</form>
</div>
</body>
<script>
class FormValidator {
constructor(form, fields) {
this.form = form;
this.fields = fields;
}
initialize() {
// this.validateOnEntry(); // 실시간 감지
this.validateOnSubmit();
}
validateOnSubmit() {
let self = this;
this.form.addEventListener("submit", (e) => {
e.preventDefault();
self.fields.forEach((field) => {
const input = document.getElementsByName(`${field}`);
if (input[0].type == "checkbox") {
self.validateFields_Checkbox(input[0], field);
} else if (input[0].type == "select-one") {
self.validateFields_Selectbox(input[0]);
} else {
self.validateFields(input);
}
});
});
}
validateOnSubmit2() {
// e.preventDefault();
let self = this;
self.fields.forEach((field) => {
const input = document.getElementsByName(`${field}`);
self.validateFields(input);
if (input[0].type == "checkbox") {
self.validateFields_Checkbox(input[0], field);
} else if (input[0].type == "select-one") {
self.validateFields_Selectbox(input[0]);
} else {
self.validateFields(input);
}
});
}
validateOnEntry() {
let self = this;
this.fields.forEach((field) => {
const input = document.getElementsByName(`${field}`);
input.addEventListener("input", (event) => {
self.validateFields(input);
});
});
}
validateFields(fields) {
let formval_min = fields[0].getAttribute("formval_min");
let formval_max = fields[0].getAttribute("formval_max");
fields.forEach((field) => {
if (field.value.trim() === "") {
this.setStatus(field, `${field.previousElementSibling.innerText} 을/를 입력해주세요`, "error");
} else {
if (field.value.trim() !== "") {
this.setStatus(field, null, "success");
}
if (field.type === "text") {
if (formval_max && formval_min) {
if (formval_max < field.value.trim().length || formval_min > field.value.trim().length) {
this.setStatus(field, formval_min + "자 이상 " + formval_max + "자 이하로 입력해주세요.", "error");
}
} else {
if (formval_min) {
if (formval_min > field.value.trim().length) {
this.setStatus(field, formval_min + "자 이상 입력해주세요.", "error");
}
}
if (formval_max) {
if (formval_max < field.value.trim().length) {
this.setStatus(field, formval_max + "자 이하로 입력해주세요.", "error");
}
}
}
}
if (field.type === "email") {
const re = /\S+@\S+\.\S+/;
if (re.test(field.value)) {
this.setStatus(field, null, "success");
} else {
this.setStatus(field, "이메일 형식이 맞지 않습니다.", "error");
}
}
if (field.id === "password_confirmation") {
const passwordField = this.form.querySelector("#password");
if (field.value.trim() == "") {
this.setStatus(field, "비밀번호를 입력해주세요.", "error");
} else if (field.value != passwordField.value) {
this.setStatus(field, "비밀번호 두개가 일치하지 않습니다.", "error");
} else {
this.setStatus(field, null, "success");
}
}
}
});
}
validateFields_Checkbox(field, checkboxName) {
const selectedCheckboxLength = document.querySelectorAll(`input[name="${checkboxName}"]:checked`).length;
let formval_min = field.getAttribute("formval_min");
let formval_max = field.getAttribute("formval_max");
if (selectedCheckboxLength == 0) {
this.setStatus(field, `${field.parentElement.parentElement.querySelector("label").innerText} 을/를 선택해주세요`, "error");
} else {
this.setStatus(field, null, "success");
}
if (formval_max && formval_min) {
if (formval_max < selectedCheckboxLength || formval_min > selectedCheckboxLength) {
this.setStatus(field, formval_min + "개 이상 " + formval_max + "개 이하로 선택해주세요.", "error");
}
} else {
if (formval_min) {
if (formval_min > selectedCheckboxLength) {
this.setStatus(field, formval_min + "개 이상 선택해주세요.", "error");
}
}
if (formval_max) {
if (formval_max < selectedCheckboxLength) {
this.setStatus(field, formval_max + "개 이하로 선택해주세요.", "error");
}
}
}
}
validateFields_Selectbox(field) {
if (field.value.trim() === "") {
this.setStatus(field, `${field.previousElementSibling.previousElementSibling.innerText} 을/를 선택해주세요`, "error");
} else {
this.setStatus(field, null, "success");
}
}
setStatus(field, message, status) {
const successIcon = field.parentElement.querySelector(".icon-success") ? field.parentElement.querySelector(".icon-success") : field.parentElement.parentElement.querySelector(".icon-success");
const errorIcon = field.parentElement.querySelector(".icon-error") ? field.parentElement.querySelector(".icon-error") : field.parentElement.parentElement.querySelector(".icon-error");
const errorMessage = field.parentElement.querySelector(".error-message")
? field.parentElement.querySelector(".error-message")
: field.parentElement.parentElement.querySelector(".error-message");
if (status === "success") {
if (errorIcon) {
errorIcon.classList.add("hidden");
}
if (errorMessage) {
errorMessage.innerText = "";
}
successIcon.classList.remove("hidden");
field.classList.remove("input-error");
}
if (status === "error") {
if (successIcon) {
successIcon.classList.add("hidden");
}
errorMessage.innerText = message;
errorIcon.classList.remove("hidden");
field.classList.add("input-error");
}
}
}
const form = document.querySelector(".form");
// name 명
const fields = ["username", "email", "password", "password_confirmation", "checkbox00", "checkbox01", "selectBox0"];
const validator = new FormValidator(form, fields);
validator.initialize();
</script>
</html>
이렇게 만들었는데 여기에서 입맛에 맞게 추가수정을 하면 될거같다
'코딩 공부 > HTML' 카테고리의 다른 글
[HTML] - iframe을 JS로 제어하고 css를 맘껏 써보자! (0) | 2023.01.04 |
---|---|
보여주는 속성을 지정하기 visibility (0) | 2022.06.08 |
html 간단한 모션을 만들어보기 -transition (0) | 2022.06.08 |
html - 반응형 웹 제작을 효율적으로 하는 법 rem (0) | 2022.05.19 |
css 로 네온사인 효과 주기 (0) | 2022.05.18 |