Input 입력 막기 - Input iblyeog maggi

<input type="text" />

위와 같은 input 개체가 있을 때,

글 쓰지 못하게 막는 방법 중, 

대표적으로 readonly 와 disabled 가 있다.

이 둘 모두 input 타입의 속성이다.

따라서 다음과 같이 사용할 수 있다.

using html

<input type="text" id="txt1" readonly />        
<input type="text" id="txt2" disabled />

<textarea id="txtfield1" readonly ></textarea>
<textarea id="txtfield2" disabled ></textarea>

<input type="password" id="pass1" readonly />
<input type="password" id="pass2" disabled />

using script

var oEle1 = document.getElementById('txt1') ;
var oEle2 = document.getElementById('txt2') ;
var oEle3 = document.getElementById('txtfield1') ;
var oEle4 = document.getElementById('txtfield2') ;
var oEle5 = document.getElementById('pass1') ;
var oEle6 = document.getElementById('pass2') ;

//

"readOnly" 로서 대문자임에 유의한다.
oEle1.readOnly = true ;
oEle2.readOnly = true ;
oEle3.readOnly = true ;
oEle4.readOnly = true ;
oEle5.readOnly = true ;
oEle6.readOnly = true ;

oEle1.disabled = true ;
oEle2.disabled = true ;
oEle3.disabled = true ;
oEle4.disabled = true ;
oEle5.disabled = true ;
oEle6.disabled = true ;

comment : 'readonly' , 'disabled' 둘다 사용자의 입력을 하지 못하게 막는 기능은 동일하지만,

form 안에서 사용하였을 경우,

'readonly' 는 form 전송이 가능하지만,

'disabled' 는 form 전송시 값이 전달되지 않는다.

유의하기 바란다.

출처: http://jwizard.tistory.com/35

티스토리 뷰

두가지 방법이 있는데, 하나는 readonly를 이용하는 방법과 disabled를 이용하는 방법이 있다.


<input type="text" class="form-control" id="uName" name="uName" readonly>

<input type="text" class="form-control" id="uName" name="uName" disabled>

그런데!!! 여기서 주의할 점은 disabled 는 폼으로 값이 전송이 안된다. 폼으로 데이터를 전송하고 싶으면 반드시 readonly 를 써야한다. ㅠㅠ 이걸로 2시간 날렸다...

Input 입력 막기 - Input iblyeog maggi

안녕하세요, Einere입니다.

(광고 차단 기능을 꺼주시면 감사하겠습니다.)


움짤이 버벅거리거나 잘 보이지 않는다면 클릭해주세요.

요구사항

프로젝트에서 특정 input창에 왼쪽 방향키, 오른쪽 방향키, 백스페이스를 제외한 문자가 입력되는 것을 방지해야 했습니다. 

저는 '음.. 조금 귀찮긴 하겠지만 할만하네' 라고 생각했습니다. 하지만 이때의 저는 험난한 여정이 시작될 것을 몰랐습니다..

첫 구현

inputElement.addEventListener("keydown", function handleKeyDown(e) {
  console.log("key down", e.key, e.code);
  
  const whiteList = ['ArrowLeft', 'ArrowRight', 'Backspace'];
  
  if (!whiteList.some(code => e.code === code)) {
    e.preventDefault();
    return;
  }
      
  if (e.code === 'Backspace') {
    e.preventDefault();
    return;
  }
}

whiteliste.code 를 이용해, 왼쪽 화살표, 오른쪽 화살표, 백스페이스를 제외한 키는 입력을 방지하도록 해보겠습니다.

Input 입력 막기 - Input iblyeog maggi
영어, 캡스락, 한글, 방향키, 백스페이스

한글 빼고는 잘 막아집니다. 그럼 한글 입력 방지는 어떻게 해야 할까요?

정규표현식과 preventDefault()를 이용해보자

일단 요구사항은 허용된 키 이외에는 모두 입력을 막아야 합니다. 영어는 잘 막아지니까, 영어가 아닌 것들은 싹 다 쳐내도록 해보겠습니다.

inputElement.addEventListener("keydown", function handleKeyDown(e) {
  console.log("key down", e.key, e.code);
  
  const notEngExp = /[^A-Za-z]/g;
  const isNotEng = notEngExp.test(e.key);

  if (isNotEng) {
    console.log("not english");
    e.preventDefault();
    return;
  }
}

위 코드로, 영어가 아닌 키 입력이 잘 막아지는지 테스트 해보겠습니다.

Input 입력 막기 - Input iblyeog maggi
정규 표현식은 작동하지만..

정규표현식은 잘 되지만 여전히 `preventDefault()` 로 한글 입력 방지는 안됩니다. 🤔

구글링을 하다 보니, 한글은 조합글자라서 keypress로 핸들링해야 한다는 글이 있었습니다. 그렇다면, 다음 코드로 테스트를 해봅시다.

inputElement.addEventListener("keypress", function handleKeyPress(e) {
  console.log("key press", e.key, e.code);

  const whiteList = ["ArrowLeft", "ArrowRight", "Backspace"];
  const notEngExp = /[^A-Za-z]/g;
  const allowedKey = whiteList.some((code) => e.code === code);
  const isNotEng = notEngExp.test(e.key);

  if (!allowedKey) {
    console.log("not allowed");
    e.preventDefault();
    return;
  }

  if (e.code === "Backspace") {
    e.preventDefault();
    return;
  }

  if (isNotEng) {
    console.log("not english");
    e.preventDefault();
    return;
  }
}
Input 입력 막기 - Input iblyeog maggi

backspace는 콘솔에 출력되는게 아무것도 없는 것으로 보아, non character 문자들은  keypress 이벤트에 걸리지도 않는 것 같습니다.

한글도 콘솔에 찍히는게 없는 것으로 봐서는 이벤트에 걸리진 않지만, 그렇다고 입력이 방지되지는 않았습니다.

정규 표현식과 replace()를 이용한 방법

inputElement.addEventListener("keyup", function (e) {
  console.log("key up", e.key, e.code);

  const whiteList = ["ArrowLeft", "ArrowRight", "Backspace"];
  const notEngExp = /[^A-Za-z]/g;
  const allowedKey = whiteList.some((code) => e.code === code);
  const isNotEng = notEngExp.test(e.key);
  const koreanExp = /[ㄱ-ㅎㅏ-ㅣ가-힣]/g;

  // if (!allowedKey) {
  //   console.log("not allowed");
  //   e.preventDefault();
  //   return;
  // }

  // if (e.code === "Backspace") {
  //   e.preventDefault();
  //   return;
  // }

  if (isNotEng) {
    console.log("not english");
    e.preventDefault();
    e.target.value = e.target.value.replace(koreanExp, "");
    return;
  }
});

keyup 이벤트 핸들러를 정의해줍니다.

Input 입력 막기 - Input iblyeog maggi
내눈!!

음.. 엄밀히 말하면 막는 게 아니라 지우는거긴 합니다. UX도 구리구요.. 😵

W3 명세에 따르면

Input 입력 막기 - Input iblyeog maggi

W3의 명세의 Canceling Composition Events 섹션을 보면, keydown 이벤트가 캔슬되면 keydown 이벤트의 결과로 인해 발생할 수 있는 모든 composition event는 dispatch되지 않아야 한다고 합니다.

즉, input 요소에 @keydown.prevent만 해줘도 모든 컴포지션 이벤트를 막을 수 있다는 것이죠. 그러나 code sandbox를 통해 실험한 결과, 컴포지션 이벤트들이 아주 잘 dispatch 되었습니다.

Input 입력 막기 - Input iblyeog maggi
keydown을 막아도.. 컴포지션 이벤트가 발생해..

아마 명세를 따르지 않았거나,  한글만 예외적이거나.. 라고 생각합니다.

그런데.. 명세를 조금 더 읽어보니, compositionstart 이벤트 섹션에 다음과 같은 글이 쓰여져 있었습니다.

Some IMEs do not support cancelling an in-progress composition session (e.g., such as GTK which doesn’t presently have such an API). In these cases, calling preventDefault() will not stop this event’s default action.

헉.. 몇몇 IMEInput Method Editor는 진행중인 컴포지션 세션을 종료하는 것을 지원하지 않으며, 이 경우 preventDefault() 로 해당 이밴트의 기본 액션을 멈출 수 없다고 합니다. 😰

완벽하진 않지만 막을 수 있어

조금 더 찾아보니 compositionstart 이벤트 핸들러에서, 다음과 같이 한글(조합 문자) 입력을 방지할 수 있긴 합니다.

composition event를 포함한 input 요소의 이벤트들에 대한 더 자세한 정보는 [JS] input element event 를 참고해주세요!

inputElement.addEventListener("keydown", function keyDownHandler (e) {
  console.log("key down", e.key, e.code);

  const whiteList = ["ArrowLeft", "ArrowRight", "Backspace"];
  const allowedKey = whiteList.some((code) => e.code === code);

  if (!allowedKey) {
    console.log("not allowed");
    e.preventDefault();
    return;
  }

  if (e.code === "Backspace") {
    e.preventDefault();
    return;
  }
});
inputElement.addEventListener(
  "compositionstart",
  function handleCompositionStart(e) {
    const self = this;
    self.blur();

    requestAnimationFrame(function () {
      self.focus();
    });
  }
);

const button = document.getElementById("check");
const span = document.getElementById("span");
button.addEventListener("click", function clickHandler(e) {
  span.textContent = inputElement.value;
});
Input 입력 막기 - Input iblyeog maggi

물론 광클하면 못막긴 합니다만.. 나름 막을 수는 있네요..