모든 강의를 무료로 볼 수 있어요. 회원가입 없이도 학습 가능합니다.

19강 / 전체 22강

폼과 입력값

12분 읽기 조회 4

다양한 입력 요소(text·checkbox·radio·select)에서 값 읽기, submit 이벤트 처리, 클라이언트 사이드 유효성 검사, 실시간 피드백 패턴까지 폼 처리를 완성합니다.

🎯 학습 목표

이 강을 마치면 다음을 할 수 있습니다.

  • 텍스트 입력, 체크박스, 라디오 버튼, 셀렉트 박스에서 값을 읽을 수 있습니다.
  • 폼 제출 이벤트를 가로채 자바스크립트로 처리할 수 있습니다.
  • 간단한 클라이언트 사이드 유효성 검사를 구현할 수 있습니다.
  • 실시간 입력 피드백을 제공하는 UI를 만들 수 있습니다.

📝 텍스트 입력값 읽기

이 섹션에서는 <input>과 <textarea>에서 사용자가 입력한 값을 읽는 방법을 살펴보겠습니다.

폼의 가장 기본은 텍스트 입력입니다. 자바스크립트에서 입력 요소의 현재 값은 .value 속성으로 읽고 씁니다. 18강에서 배운 이벤트와 결합하면 실시간 처리가 가능합니다.

// HTML:
// <input type="text" id="username" placeholder="이름 입력">
// <input type="number" id="age" min="0" max="120">
// <input type="password" id="pwd">
// <textarea id="bio"></textarea>

const usernameInput = document.querySelector("#username");
const ageInput = document.querySelector("#age");
const bioArea = document.querySelector("#bio");

// 값 읽기
console.log(usernameInput.value);  // 현재 입력값 (문자열)
console.log(ageInput.value);       // 숫자여도 문자열! "25"
console.log(Number(ageInput.value)); // 숫자로 변환 필요

// 값 설정
usernameInput.value = "홍길동";

// 포커스 & 초기화
usernameInput.focus();   // 커서 이동
usernameInput.select();  // 텍스트 전체 선택
usernameInput.value = "";  // 초기화

// 실시간 글자 수 카운터
const bioDisplay = document.querySelector("#bio-count");
bioArea.addEventListener("input", (e) => {
  const len = e.target.value.length;
  bioDisplay.textContent = `${len} / 200자`;
  bioDisplay.style.color = len > 200 ? "red" : "gray";
});

// 실시간 검색 (디바운스 적용)
let timer;
usernameInput.addEventListener("input", (e) => {
  clearTimeout(timer);  // 이전 타이머 취소
  timer = setTimeout(() => {
    console.log(`검색: ${e.target.value}`);  // 입력 멈추고 300ms 후 실행
  }, 300);
});

중요한 점은 input.value는 항상 문자열을 반환한다는 것입니다. type="number"로 설정해도 값은 문자열로 반환됩니다. 숫자 계산에 사용하려면 Number(), parseInt(), parseFloat()으로 변환해야 합니다. 디바운스(Debounce) 패턴은 실시간 검색에서 필수입니다. 사용자가 타이핑할 때마다 API를 호출하면 서버에 부담이 크므로, 입력이 멈춘 후 일정 시간이 지났을 때만 처리하는 패턴입니다. 22강 타이머에서 자세히 다룹니다.

☑️ 체크박스와 라디오 버튼

이 섹션에서는 체크박스와 라디오 버튼처럼 선택/해제 방식의 입력 요소를 다루는 방법을 살펴보겠습니다.

체크박스와 라디오 버튼은 텍스트 입력과 달리 .value가 아닌 .checked 속성으로 선택 여부를 확인합니다. 이 차이를 이해하는 것이 중요합니다.

// HTML:
// <input type="checkbox" id="agree" value="agree">
// <label for="agree">약관에 동의합니다</label>
//
// <input type="radio" name="gender" value="male" id="male">
// <label for="male">남성</label>
// <input type="radio" name="gender" value="female" id="female">
// <label for="female">여성</label>

// 체크박스
const agreeBox = document.querySelector("#agree");

console.log(agreeBox.checked);  // true/false (선택 여부)
console.log(agreeBox.value);    // "agree" (value 속성값, 체크 여부 무관)

agreeBox.addEventListener("change", (e) => {
  console.log(e.target.checked);  // true (체크) or false (해제)
  submitBtn.disabled = !e.target.checked;  // 미동의 시 버튼 비활성화
});

// 여러 체크박스 — 선택된 것만 수집
const hobbies = document.querySelectorAll("input[name='hobby']");
const selected = [...hobbies]
  .filter(cb => cb.checked)
  .map(cb => cb.value);
console.log(selected);  // ["독서", "코딩"] 등

// 라디오 버튼
const genderRadios = document.querySelectorAll("input[name='gender']");

genderRadios.forEach(radio => {
  radio.addEventListener("change", (e) => {
    if (e.target.checked) {
      console.log(`선택: ${e.target.value}`);  // "male" or "female"
    }
  });
});

// 현재 선택된 라디오 값 읽기
const selectedGender = document.querySelector("input[name='gender']:checked");
console.log(selectedGender?.value);  // "male" or null (없으면 null)

라디오 버튼 그룹에서 현재 선택된 값을 읽을 때 :checked CSS 가상 클래스를 선택자로 사용하는 패턴이 편리합니다. 선택된 것이 없으면 null을 반환하므로 옵셔널 체이닝 ?.value를 함께 사용합니다. 체크박스에서 여러 개를 선택해 배열로 수집할 때는 querySelectorAll로 모두 선택한 뒤 배열로 변환해 filter(cb => cb.checked)로 걸러내는 패턴을 사용합니다.

📋 셀렉트 박스

이 섹션에서는 드롭다운 선택 요소인 <select>와 <option>을 다루는 방법을 살펴보겠습니다.

// HTML:
// <select id="country">
//   <option value="">선택하세요</option>
//   <option value="kr">대한민국</option>
//   <option value="jp">일본</option>
//   <option value="us">미국</option>
// </select>

const select = document.querySelector("#country");

// 현재 선택된 값
console.log(select.value);   // "kr" 등 선택된 option의 value
console.log(select.options[select.selectedIndex].text); // 표시 텍스트

// 변경 이벤트
select.addEventListener("change", (e) => {
  console.log(e.target.value);  // 새로 선택된 값
  if (!e.target.value) {
    console.log("선택하세요 항목 선택됨");
  }
});

// 동적으로 옵션 추가
const newOption = document.createElement("option");
newOption.value = "cn";
newOption.textContent = "중국";
select.appendChild(newOption);

// 다중 선택 — multiple 속성
// <select multiple id="tags">...</select>
const multiSelect = document.querySelector("#tags");
const selectedValues = [...multiSelect.selectedOptions]
  .map(opt => opt.value);
console.log(selectedValues);  // 선택된 모든 값 배열

📤 폼 제출 처리

이 섹션에서는 폼 전체를 처리하는 submit 이벤트와 여러 입력값을 한 번에 수집하는 방법을 살펴보겠습니다.

18강에서 event.preventDefault()로 폼 기본 동작을 막는 법을 배웠습니다. 이를 폼의 모든 입력값 수집과 결합하면 완전한 폼 처리 로직을 만들 수 있습니다.

// HTML:
// <form id="signup-form">
//   <input type="text"     name="username" required>
//   <input type="email"    name="email"    required>
//   <input type="password" name="password" minlength="8">
//   <button type="submit">가입하기</button>
// </form>

const form = document.querySelector("#signup-form");

form.addEventListener("submit", (event) => {
  event.preventDefault();  // 페이지 새로고침 막기

  // 방법 1: FormData로 수집 (name 속성 필요)
  const formData = new FormData(form);
  console.log(formData.get("username"));
  console.log(formData.get("email"));

  // Object로 변환
  const data = Object.fromEntries(formData);
  console.log(data);  // { username: "...", email: "...", password: "..." }

  // 방법 2: 개별 요소에서 직접 읽기
  const username = form.querySelector("[name='username']").value.trim();
  const email    = form.querySelector("[name='email']").value.trim();
  const password = form.querySelector("[name='password']").value;

  // 유효성 검사 후 처리
  if (validate({ username, email, password })) {
    console.log("서버로 전송!", { username, email });
    // fetch로 API 호출 (26강에서 학습)
  }
});

function validate({ username, email, password }) {
  const errors = [];

  if (!username || username.length < 2) {
    errors.push("이름은 2자 이상이어야 합니다");
  }
  if (!email.includes("@")) {
    errors.push("올바른 이메일 형식이 아닙니다");
  }
  if (password.length < 8) {
    errors.push("비밀번호는 8자 이상이어야 합니다");
  }

  if (errors.length > 0) {
    alert(errors.join("\n"));  // 실제 서비스에서는 UI 표시 권장
    return false;
  }
  return true;
}

FormData는 폼의 모든 입력을 한 번에 수집하는 브라우저 내장 클래스입니다. Object.fromEntries(formData)로 일반 객체로 변환하면 다루기 쉽습니다. 단, type="file"의 파일 객체나 체크박스 그룹은 별도 처리가 필요합니다. 유효성 검사를 서버에만 맡기지 않고 클라이언트에서도 수행하면 불필요한 서버 요청을 줄이고 즉각적인 피드백을 제공할 수 있습니다. 다만 클라이언트 검사는 우회가 가능하므로 서버 검사를 반드시 병행해야 합니다.

📝 핵심 요약

19강에서 배운 내용을 정리해 보겠습니다.

입력 요소값 읽기이벤트
text/number/passwordel.valueinput(실시간), change(확정)
textareael.valueinput
checkboxel.checkedchange
radioel.checked / :checked 선택자change
selectel.valuechange
폼 전체new FormData(form)submit (+ preventDefault)

다음 강인 20강 — 요소 생성·삭제에서는 자바스크립트로 HTML 요소를 동적으로 만들고 DOM에 추가하거나 제거하는 방법을 배웁니다. createElement, appendChild, remove를 마스터하면 17강의 innerHTML보다 안전하고 강력한 방식으로 UI를 동적으로 구성할 수 있습니다!

관련 주제

  • 폼 입력값 읽기
  • submit 이벤트
  • 유효성 검사
  • checkbox radio select
  • 실시간 입력 피드백
  • 개발·프로그래밍
  • 개발·프로그래밍 강의
  • 자바스크립트 기초 30강 — 웹을 움직이는 언어
  • 무료강의
  • 무료 온라인 강의
  • NUGUNA
  • 누구나

📚 시리즈 전체 공유

자바스크립트 기초 30강 — 웹을 움직이는 언어

이 강의가 속한 시리즈는 총 22강, 모두 무료입니다. 처음부터 배우려는 동료에게 시리즈 전체를 알려 주세요.

댓글

0/1000

불러오는 중...