Valid State Detection
목적
--valid
, --invalid
상태 클래스를 추가/제거해서 아래 이미지 처럼 경고 메세지가 뜨게 한다.



설계
<div class="emailContainer__block">
<input type="email" id="userEmail__main" />
<label for="userEmail__main">이메일 주소</label>
<span role="alert" aria-live="off">정확한 이메일 주소를 입력하세요.</span>
</div>
변수 선언
const emailContainerNode = document.querySelectorAll('.emailContainer__block')
const emailInputNode = document.querySelectorAll('.emailContainer__block input')
const INVALID_CLASS = 'emailContainer__block--invalid'
const VALID_CLASS = 'emailContainer__block--valid'
const emailInputNodeArr = Array.from(emailInputNode)
사용된 기능
Array.from() → 유사배열 배열화
Element.matches() → 해당 요소에 전달한 선택자가 있는지 확인
HTMLInputElement.select () → <input>의 모든 텍스트를 선택
e.target.value → <input>에 입력한 값을 알 수 있다.
Window: blur event → 포커스를 잃었을 때
방법
<input>
에'input'
이벤트 바인딩을 한다.matches()
메서드를 사용해서':invalid'
선택자가 있는지 확인한다.boolean
값으로 반환하기 때문에 조건 문의 조건으로 사용한다.
위의 메서드를 조건으로 해서
.emailContainer__block
에.emailContainer__block--vaild
,.emailContainer__block--invalid
상태 클래스를 추가/제거하도록 한다.parentNode
를 사용해서 바로 위의 요소를 변수에 담는다.
emailInputNodeArr.forEach(function (item, index) {
item.addEventListener('input', (e) => {
const isInvalid = e.target.matches(':invalid')
const targetParentNode = e.target.parentNode
if (isInvalid) {
// 유효하지 않은 상태
targetParentNode.classList.remove(VALID_CLASS)
targetParentNode.classList.add(INVALID_CLASS)
} else {
// 유효한 상태
targetParentNode.classList.remove(INVALID_CLASS)
targetParentNode.classList.add(VALID_CLASS)
}
})
})
문제 (1)
<input>
에 텍스트가 아닌 공백만 있을 때, label
이 원래 자리로 내려오지 않는 이슈


emailInputNodeArr.forEach(function (item, index) {
item.addEventListener('input', (e) => {
const targetParentNode = e.target.parentNode
// 사용자가 입력한 정보의 글자 개수가 빈 공백을 지우고 나서 0일 때 valid 상태가 아님을 인지
if (e.target.value.trim().length === 0) {
targetParentNode.classList.remove(VALID_CLASS)
}
})
// input이 포커스 상태가 아닐 때, 사용자가 입력한 정보의 글자 개수가
// 빈 공백을 지우고 나서 0일 때 valid 상태가 아님을 인지
item.addEventListener('blur', (e) => {
if (e.target.value.trim().length === 0) {
e.target.parentNode.classList.remove(VALID_CLASS)
}
})
})
문제 (2)
입력을 위해 <input>
을 클릭 했을 때 label
이 선택되었다. 그래서 'focus'
이벤트가 발생했을 때 select()
메서드에 setTimeout()
을 사용해서 시간을 추가한다.

// label의 text가 선택되는 것을 방지 하기 위해 포커스 이벤트에 시간 추가
item.addEventListener('focus', (e) => {
if (e.target.value.trim().length === 0) {
window.setTimeout(() => e.target.select())
}
})
결론
const emailContainerNode = document.querySelectorAll('.emailContainer__block')
const emailInputNode = document.querySelectorAll('.emailContainer__block input')
const INVALID_CLASS = 'emailContainer__block--invalid'
const VALID_CLASS = 'emailContainer__block--valid'
const emailInputNodeArr = Array.from(emailInputNode)
emailInputNodeArr.forEach(function (item, index) {
item.addEventListener('input', (e) => {
const isInvalid = e.target.matches(':invalid')
const targetParentNode = e.target.parentNode
if (isInvalid) {
// 유효하지 않은 상태
targetParentNode.classList.remove(VALID_CLASS)
targetParentNode.classList.add(INVALID_CLASS)
} else {
// 유효한 상태
targetParentNode.classList.remove(INVALID_CLASS)
targetParentNode.classList.add(VALID_CLASS)
}
// 사용자가 입력한 정보의 글자 개수가 빈 공백을 지우고 나서 0일 때 valid 상태가 아님을 인지
if (e.target.value.trim().length === 0) {
targetParentNode.classList.remove(VALID_CLASS)
}
})
// input이 포커스 상태가 아닐 때, 사용자가 입력한 정보의 글자 개수가 빈 공백을 지우고 나서 0일 때 valid 상태가 아님을 인지
item.addEventListener('blur', (e) => {
if (e.target.value.trim().length === 0) {
e.target.parentNode.classList.remove(VALID_CLASS)
}
})
// label의 text가 선택되는 것을 방지 하기 위해 포커스 이벤트에 시간 추가
item.addEventListener('focus', (e) => {
if (e.target.value.trim().length === 0) {
window.setTimeout(() => e.target.select())
}
})
})
Last updated
Was this helpful?