폼 입력과 이벤트 위임
입력값을 읽고 검사합니다. 위임으로 여러 요소를 한 번에 다룹니다.
입력을 받고, 늘어나는 요소를 다룹니다
이 단원에서 두 가지를 다룹니다. 입력 칸에서 값을 읽어 검사하는 것과, 나중에 만들어질 요소까지 한 번에 다루는 것입니다.
두 번째가 이벤트 위임 입니다. 4.6 처럼 항목을 계속 만들어 넣는 화면에서는 만들 때마다 이벤트를 붙일 수 없습니다.
입력값 읽고 검사하기
const input = document.querySelector("#name"); const add = document.querySelector("#add"); const msg = document.querySelector("#msg"); add.addEventListener("click", () => { const value = input.value.trim(); if (value === "") { msg.textContent = "이름을 입력해 주세요"; return; } msg.textContent = `${value}님 안녕하세요`; input.value = ""; }); add.click(); console.log(msg.textContent); input.value = " 홍길동 "; add.click(); console.log(msg.textContent);
value 는 언제나 글자입니다. 앞뒤 빈칸을
trim 으로 걷어내야 빈칸만 넣은 것을 걸러 낼 수
있습니다(1.5).
맞지 않으면 return 으로 그 자리에서 끝냅니다.
else 로 감싸는 것보다 읽기 좋습니다(7.3 에서 다시
다룹니다).
왜 위임이 필요한가
아래는 동작하지 않는 코드입니다. 이벤트를 붙일 때 있던 항목에만 붙었고, 뒤에 만든 항목에는 붙지 않았습니다.
const list = document.querySelector("#list"); document.querySelectorAll("#list button").forEach(btn => { btn.addEventListener("click", () => console.log("지웁니다")); }); const li = document.createElement("li"); li.innerHTML = "<button>지우기</button> 공책"; list.append(li); list.querySelectorAll("button").forEach(btn => btn.click());
단추가 둘인데 한 번만 나왔습니다. 나중에 만든 단추에는 이벤트가 없기 때문입니다.
부모 하나에만 붙입니다
누른 자리에서 일어난 일은 부모에게도 전해집니다. 그래서 부모에 한 번만
붙여 두고, event.target 으로 어디를 눌렀는지
가리면 됩니다(4.5).
const list = document.querySelector("#list"); list.addEventListener("click", event => { const btn = event.target.closest("button"); if (!btn) return; const li = btn.closest("li"); console.log(`${li.querySelector(".name").textContent} 지웠습니다`); li.remove(); }); list.querySelector("button").click(); console.log(list.children.length);
closest 는 자기 자신부터 위로 올라가며 선택자에 맞는
가장 가까운 조상을 찾습니다. 단추 안의 글자를 눌러도 단추를 찾아 줍니다.
if (!btn) return; 이 중요합니다. 목록의 빈 자리를
눌렀을 때는 아무 일도 하지 않아야 합니다.
폼으로 받기
입력 칸을 form 으로 감싸면 엔터로도 보낼 수
있습니다. 다만 그대로 두면 화면이 새로 뜨므로
preventDefault 가 필요합니다(4.5).
const form = document.querySelector("#form"); form.addEventListener("submit", event => { event.preventDefault(); const value = form.querySelector("input").value.trim(); if (value === "") return; // 여기서 항목을 더합니다(4.6) });
이 예제는 실행 단추가 없습니다. 폼을 보내는 것은 화면을 옮기는 일이라 실행 자리에서 막혀 있습니다. 실제 페이지에서는 위 코드가 그대로 동작합니다.
처음에 자주 걸리는 것
항목이 늘어날수록 이벤트도 늘어납니다. 부모에 한 번만 붙이는 위임이 간단하고 빠릅니다.
단추 안의 글자나 아이콘을 누르면 target 이 그것이
됩니다. closest 로 원하는 요소까지 올라가세요.
closest 가 null 을
돌려주면 이어지는 줄에서 오류가 납니다.
if (!btn) return; 을 먼저 두세요.
TypeError: Cannot read properties of null (reading 'closest')
파트 4 미니 실습 — To-Do 목록
입력 칸·추가 단추·목록이 있습니다. 아래 넷을 모두 만드세요.
- 추가 단추를 누르면 입력한 글로 항목을 만들어 넣습니다(4.6).
- 빈칸만 넣었으면 더하지 않습니다(
trim). - 항목의 글자를 누르면
doneclass 를 켜고 끕니다(4.4). - 항목의 지우기를 누르면 그 항목을 지웁니다.
셋째와 넷째는 나중에 만들어진 항목에도 동작해야 합니다 — 위임입니다.
click 을 한 번만 붙이고, 그 안에서 closest("button") 인지 closest(".name") 인지로 갈라 처리하면 됩니다.// 위 정답을 여기에 옮겨 적고 실행해 보세요. // 실행한 뒤 미리보기 탭에서 직접 더하고 눌러 볼 수 있습니다. console.log("여기에 작성하세요");
여기까지 하면 파트 4 가 끝납니다. 다음 파트에서는 서버에서 데이터를 가져옵니다.
이 단원의 정리
- 입력 칸의
value는 언제나 글자입니다.trim으로 다듬어 검사합니다. - 맞지 않으면
return으로 먼저 끝냅니다. - 나중에 만들어질 요소까지 다루려면 부모에 한 번만 붙입니다(위임).
event.target.closest로 원하는 요소까지 올라갑니다.- 못 찾았을 때(
null)를 먼저 걸러 냅니다.