input 폼에 숫자만 입력하기 위해
보통 HTML5 스펙에 있는 input type="number" 를 사용한다.
<input type="number">
다음의 문제가 발생한다
- 타입은 number 지만 지수 표기법으로 인해 영문자 e 혹은 E 가 입력이 가능하다.
- 한글이 입력된다.
- 숫자가 아닌 값이 입력될때 input 의 value 가 null 이 아닌 아예 빈 값이 된다.
( input 에 보여지는 상태는 변화가 없다. )
KeyPress Event
한글 입력시 이벤트 자체가 발생하지 않음
그외 알파벳 및 숫자 이벤트 발생
현재 까지 입력된 키값중에 number 가 아닌 알파벳 혹은 문자 "e" 가 들어간 경우
target.value 가 빈 값이 된다. ( input 폼안에는 텍스트 존재 )
- event.key: "1", "2", "a", "b" 등
- event.code: "KeyE", "KeyA" 등
- event.target.value: 없음
KeyDown Event (한글 입력시 이벤트 발생)
- event.key:
- 숫자/ 알파벳 : "1", "2", "a", "b", "c"
- 한글 : "Process"
- event.code:
- 숫자일 경우 "Digit1" "Digit2" 의 형태
- 그외 알파벳 "KeyK", "KeyA"
- event.target.value:
- 한글일 경우 : 값 없음
Input Event (한글 입력시 이벤트 발생)
- event.data: "한", "글", "1", "2", "abc"
- event.target.value:
- 숫자: "123"
- 한글/알파벳: 값 없음
시도한 방법들
event 받아서 replace - 입력 후 리플레이스 되는 형태라서 그런지 한글은 특히 입력/삭제가 눈에 보인다.
삽질 오래하다가 아래의 방법을 찾음
https://jsfiddle.net/emkey08/zgvtjc51
기발함. 좋음. 잘됨.
이전 입력된 값을 저장했다가 숫자가 아닌 값이 들어오면 이전 값으로 돌려 놓는 형태인데
비슷한 방법을 생각했다가 잘 되지 않아서 관뒀었는데 조건문의 형태를 조금 다른것 같다.
// Restricts input for the given textbox to the given inputFilter.
function setInputFilter(textbox, inputFilter) {
["input", "keydown", "keyup", "mousedown", "mouseup", "select", "contextmenu", "drop"].forEach(function(event) {
textbox.addEventListener(event, function() {
if (inputFilter(this.value)) {
this.oldValue = this.value;
this.oldSelectionStart = this.selectionStart;
this.oldSelectionEnd = this.selectionEnd;
} else if (this.hasOwnProperty("oldValue")) {
this.value = this.oldValue;
this.setSelectionRange(this.oldSelectionStart, this.oldSelectionEnd);
} else {
this.value = "";
}
});
});
}
// Install input filters.
setInputFilter(document.getElementById("intTextBox"), function(value) {
return /^-?\d*$/.test(value); });
setInputFilter(document.getElementById("uintTextBox"), function(value) {
return /^\d*$/.test(value); });
setInputFilter(document.getElementById("intLimitTextBox"), function(value) {
return /^\d*$/.test(value) && (value === "" || parseInt(value) <= 500); });
setInputFilter(document.getElementById("floatTextBox"), function(value) {
return /^-?\d*[.,]?\d*$/.test(value); });
setInputFilter(document.getElementById("currencyTextBox"), function(value) {
return /^-?\d*[.,]?\d{0,2}$/.test(value); });
setInputFilter(document.getElementById("latinTextBox"), function(value) {
return /^[a-z]*$/i.test(value); });
setInputFilter(document.getElementById("hexTextBox"), function(value) {
return /^[0-9a-f]*$/i.test(value); });
다만 아쉬운점은 얘는 input type="text" 다.
나의 케이스는 input 폼 옆에 숫자 증가/감소 버튼이 필요했다.
즉 input type="number" 여야 했다. 별도로 화살표 UI 를 만들수는 있었지만
위의 저 코드를 활용해보는게 더 빠를 듯하여 저 코드에서 input type="number"
로 바꾸니 대번에 제대로 동작 하지 않는다..... 한글도 입력되고..
조금 살펴보니 type="number" 일때 전달되는 이벤트 형태가 type="text" 와 좀 다른것 같아
이 부분을 방어처리하니 제대로 된다. ( 결론적으로 사용한 버전 )
import {DirectiveOptions} from 'vue';
interface HTMLInputElement2 extends HTMLInputElement{
oldValue: string;
oldSelectionStart: number | null;
oldSelectionEnd: number | null;
}
export const InputNumber: DirectiveOptions = {
bind(el) {
const handler = (event: any) => {
const target: HTMLInputElement2 = (event.target as HTMLInputElement2);
const v: string = event.data || target.value;
if (/^\d*$/.test(v)) {
target.oldValue = target.value;
target.oldSelectionStart = target.selectionStart;
target.oldSelectionEnd = target.selectionEnd;
} else if (target.hasOwnProperty('oldValue')) {
target.value = target.oldValue;
if (target.type !== 'number') {
target.setSelectionRange(target.oldSelectionStart, target.oldSelectionEnd);
}
} else {
target.value = '';
}
};
el.addEventListener('input', handler);
}
};
event.data || target.value 가 존재하는 이유가 type=number 일때 숫자가 아닌 다른 값을 입력하는 케이스에
대한 방어코드다.
또한 input number 타입의 경우 오른쪽에 증가/감소 버튼이 있는데 얘를 누르면
event.data 가 전달 되지 않는다. target.value 로 체크가 가능하다.
if (target.type !== 'number') 아래는 input number 타입이 아닌 애들도 쓸수 있게
범용적으로 하려고 놔두긴했지만 현재의 경우는 크게 필요는 없을 것 같다.
'코드 > Trouble Shoot' 카테고리의 다른 글
[JS] IOS 에서 다른 이미지 사이즈 (0) | 2020.03.27 |
---|---|
[Git] 브랜치 이름 변경하기 (0) | 2020.03.24 |
[TS] has no initializer and is not definitely assigned in the constructor (0) | 2020.02.28 |
[VS Code] 파일 뷰의 indent (0) | 2020.02.28 |
노트북화면 반전 (0) | 2015.12.24 |