[html, js] input-체크박스 click 이벤트와 e.preventDefault()

진도리·2022년 12월 14일
0

실무

목록 보기
1/1

<input type='checkbox'> 의 click 이벤트를 핸들링 하던 중 발견한 사실들에 대해 정리하고자 한다.

checked 속성과 e.preventDefault()

상황

  • 체크박스를 클릭 시, 체크박스의 checked 속성이 변경되기전에 confirm() 으로 사용자의 입력에 따라 checked 속성을 변경하려 했다.

    ex) confirm() 에 '확인'을 클릭하면 checked 를 true 로, 아니면 false 로

  • 브라우저 검사 도구로 중단점을 이용해서 체크박스의 "click" 이벤트가 발생했을 때 checked 상태를 확인했는데, 체크박스의 "change" 이벤트가 발생하기도 전에 "click" 이벤트에서 이미 checked 값이 true 로 변경되어 있었다.

  • 따라서 마우스 클릭동작으로 발생하는 이벤트들을 확인해서 "click" 이벤트 전에 적절한 이벤트에서 해당 체크박스 요소의 checked 속성을 핸들링 하려고했다.

    • 어떻게 핸들링 하려고 했는데..?
      한 이벤트에서 confirm() 으로 사용자로 하여금 체크박스를 정말로 체크할건지 말건지를 결정하게 하고, confirm 의 결과를 boolean 값으로 저장하여 클릭으로 인한 이벤트 호출 스택이 끝나면, 체크박스의 checked 값을 재설정 해주려 했다.

체크박스 클릭 시(마우스) 발생하는 이벤트 순서 : "mousedown" - "focus" - "mouseup" - "click" - "change"

해결

문제 해결 과정

첫 번째 시도 - "mousedown", "mouseup" 이벤트에서 checked 값을 고정 🤔

  • 체크박스 클릭으로 발생하는 이벤트 순서를 보고 checked 속성 값이 변경되는 "click" 이벤트가 발생하기 전에 checked 값이 변경되지 않게 다룰 수 있는 이벤트는 "mousedown", "focus", "mouseup" 세개 중 하나였다.

  • 다루고 있는 레이아웃에서 타겟 체크박스의 "mousedown/up" 이벤트에서 checked 값을 고정하거나, 상태를 저장하려했다.

    checked 값을 고정 ? : "mousedown/up" 이벤트에서 confirm() 의 사용자 입력에 따라 "click" 이벤트가 발생하지 않도록
    checked 상태를 저장 ? : "mousedown/up" 이벤트에서 confirm() 의 사용자 입력에 따라 클릭 동작 이벤트 호출 스택이 끝난 후에 checked 값을 재설정

  • 🚨하지만 해당 체크박스에서 "mousedown/up" 이벤트는 발생하지 않았다..?!

<label>
    <input type="checkbox"/>
    <span><icon></icon></span>
</label>

다루고 있는 체크박스의 레이아웃의 구조는 위와 같다. 즉, <label> 클릭 시 이벤트 캡처링으로 <input type="checkbox">의 클릭을 간접적으로 발생시켰다.

"mousedown/up" 이벤트가 발생하지 않은 이유는 위와 같이 체크박스 요소의 영역이 없었고, 박스의 영역이 없으면 "mousedown/up" 이벤트가 발생하지 않는것을 확인했다.

따라서 첫 번째 방법은 폐기

두 번째 시도 - 완료 체크박스의 "click" 이벤트에서 event.preventDefault() 로 체크박스가 체크되는 것을 막음 🤘

"click" 이벤트 리스너에 e.preventDefault() 사용해서 체크박스 클릭으로 인해 발생하는 브라우저 기본동작인 체크박스의 checked 속성값이 true가 되는 것을 막고, "change" 이벤트 또한 발생하지 않게 된다.

this.checkBoxElement.addEventListener('click', e => {
    if (!confirm(MESSAGE)) e.preventDefault(); // MESSAGE  = "체크 합니까 ?"
    e.stopPropagation();
});

근데 한 가지 재밌는 사실을 발견했다.

"click" 이벤트 리스너에서 checked 값과 색은 변경된 상태지만 e.preventDefault() 를 만나면 리스너 함수가 종료되면서 checked 값과 색이 이전 값으로 되돌아온다는 것이다.


다시 체크박스의 이벤트 발생 순서를 고려해보자.

체크박스 클릭 시(마우스) 발생하는 이벤트 순서 : "mousedown" - "focus" - "mouseup" - "click" - "change"


그리고 다음 예시 코드를 보자.

예시 코드

<body>
  <input class="chkBox" type="checkbox" />
</body>
<script>
  const chkBox = document.querySelector(".chkBox");
  chkBox.addEventListener("mouseup", e => {
    console.log(`mouseup - checked value : ${chkBox.checked}`)
  });
  
  chkBox.addEventListener("click", e => {
    console.log(`click - before confirm() checked value : ${chkBox.checked}`);
    if (!confirm("체크 합니까 ?")) {
      e.preventDefault();
    }
    console.log(`click - after confirm() checked value : ${chkBox.checked}`);
    setTimeout(timeOutHandler, 2000);
  });
  
  chkBox.addEventListener("change", e => {
  	console.log(`change - checked value : ${chkBox.checked}`);
  });

  const timeOutHandler = () => {
    console.log(`after timeout - checked value : ${chkBox.checked}`);
  }
</script>

어떤 걸 보려고 만든 코드냐면,

(1). "click" 이벤트가 발생하기 직전의 "mouseup" 이벤트 리스너에서 체크박스의 checked 값을 확인
(2). "click" 이벤트 리스너에서 체크박스의 checked 값을 확인
(3). "click" 이벤트 리스너에서 e.preventDefault() 를 만난 후의 체크박스의 checked 값을 확인
(4). "click" 이벤트 리스너 밖에서 체크박스의 checked 값을 확인


결과는 다음과 같다.

취소 클릭!

(1) mouseup : false
(2) click (before e.preventDefault()) : true
(3) click (after e.preventDefault()) : true
(4) after click event listener : false


결론은 뭐냐면

  • 브라우저는 체크박스의 "click" 이벤트에서 checked 값을 변경하고
  • "change" 이벤트를 발생시킬 준비를 하다가
  • e.preventDefault()를 만나면 그 리스너가 끝난 후, checked 값을 원래의 값으로 되돌리고
  • "change" 이벤트를 발생시키지 않게되며
  • 결과적으로 checked값이 변경되지 않은 것 처럼 보이게 한다는 것을 알게되었다!

TakeAway

  • 최초엔, 체크박스의 "change" 이벤트에 checked 값이 변경되는줄 알았는데
  • 그게 아니었고, "click" 이벤트에서 checked 값이 true 로 변경되어 있었으며
  • e.preventDefault() 를 만나도 리스너가 끝나기 전까지는 true로 유지하고 있어서
  • 다른 해결방법들을 시도했지만 별로거나 구현할 수 없어서 끙끙 앓고있다가
  • e.preventDefault() 로 인한 브라우저의 동작을 이해하려고 해보니 문제를 해결할 수 있었다!

사실 체크박스의 클릭동작막기는 mdn-e.preventDefaut 기본예제 에 예시로 나와있었지만, "change" 가 아닌 "click" 이벤트에서 checked 가 이미 변경되어 있는 예상하지 못한 상황이 발생해서 몇개 중단점을 찍어 브라우저 동작을 확인해보니 재밌는 사실을 발견할 수 있는 좋은 기회가 된 것 같다.

profile
매일 작은 보폭이라도 앞으로.

0개의 댓글

관련 채용 정보