사용자가 전화번호를 입력할 때 지정된 전화번호 길이만큼만 입력할 수 있도록 제한하고 싶다!
<input type="number" maxLength={13} />
처음엔 기존에 다른 input 창에서 사용하던 대로 maxLength
를 사용하려고 했다. 하지만 maxLength
를 지정해도 input에는 무한대로 입력이 가능했다. maxLength
를 잘못 입력했나 싶어서 몇 번이나 다시 작성했지만 결과는 달라지지 않았다. 그래서 바로 검색해보니,
음, 안되는 게 맞았다. maxLength는 text 타입의 input에만 작동하는 것이었다. 한 가지의 배움을 가지고 해당 블로그에 제시된 방법 중에 간단해보이는 두 번째 방법을 시도했다.
<input type="number" max="13" />
하지만 두 번째 시도라고 이름 붙인 만큼, 해당 코드도 작동하지 않았다. 처음엔 max
만 적어서 그런가 싶어서 min
을 함께 작성해보기도 하고, max
속성의 타입이 숫자인지 문자열인지 모르겠어서 두 가지 방법도 모두 적용해보았으나 별 다른 진전이 없었다. 또 안되는 이유를 찾아야했다.
블로그를 처음부터 찬찬히 읽고 적용했다면 이런 일이 없었을 것을... min
, max
가 숫자 타입의 input을 위한 것은 맞지만 직접 입력에 대해서는 적용이 안된다. 두 속성은 값을 선택하는 방식으로 숫자 input을 사용할 때 값의 범위를 설정해주는 속성이었던 것이다. 그러므로 직접 입력하는 방식을 취할 때에는 사용할 수 없었다.
<input onChange={(e) =>{ if(e.target.value.length >= max_length) return; }
type="number" />
좋은 코드인지는 모르겠으나 잘 돌아가는 해결방법은 바로 onChange
에서 입력값의 길이를 항상 비교하여 최대 자릿수보다 길면 더이상 입력할 수 없게 막는 것이었다. 하지만 조금 더 의미있는 코드를 작성해보기 위해 이번엔 pattern
을 사용하는 방식을 적용해보게 되는데,,
onChange
이벤트에 조건문을 삽입하는 것으로 마무리지을 수도 있지만, 전화번호 입력칸을 좀 더 완벽하게 (디자인대로) 만들기 위해서는 자동 빈칸 입력도 적용해야 했다. 예를 들면 사용자가 전화번호를 01012345678
이라고 띄어쓰기 없이 입력하더라도 실시간으로 빈칸을 입력하여 결과적으로 010 1234 5678
이 되도록 하는 것이었다. 한국 사용자의 전화번호만 고려한다면 구글에 있는 블로그들을 참고하여 금방 끝낼 수 있었겠지만, 전세계의 전화번호 형식을 모두 고려해야 했기에 동적인 방법을 찾아야했다.
다양한 블로그에서 input의 validation은 pattern 속성을 활용하라는 글을 많이 봤다. 그래서 처음엔 pattern을 적용하는 방식을 이용하기 위해 모든 나라의 전화번호의 pattern을 가져오는 함수까지 만들었다. 하지만.. 위의 인용구에서 볼 수 있듯이 pattern 속성은 number type의 input에서는 사용할 수 없어서 적용이 어려웠다. 더불어 pattern의 경우 폼 제출시 validation을 하기 때문에 실시간 적용을 원하는 디자인에 알맞지 않았다. 다른 방법을 찾아야했다.
전세계의 전화번호 포맷 등 다양한 정보를 불러올 수 있는 라이브러리 : libphonenumber-js
이 라이브러리를 사용하여 전세계의 전화번호 형식을 가져올 수 있었기 때문에 여기서 다시 출발하기로 했다. 내가 생각해낸 방법은 입력된 value의 length값을 index 값으로 활용하여 sample에서 해당 인덱스의 값이 띄어쓰기이면 띄어쓰기를 입력하는 형식이었다. 원하는 대로 잘 돌아가는 듯 했으나.. 알고보니 type이 text로 되어 있어서 잘 돌아가고 있던 것이었으므로 type을 number로 바꿨더니 띄어쓰기를 아예 받아주지 않았다. 괘씸한 놈 하지만 이 방식이 가장 괜찮다고 판단하였기 때문에 그냥 type은 text로 두고 onChange에서 들어오는 문자열값이 number인지 확인하는 형식을 도입하기로 마음 먹었다. 그로 인해 타이핑되는 value가 숫자인지 아닌지 판별하는 validation도 여기에 포함되게 되었다.
onChange={(e) => {
//Check the length of input value is longer than phone number example or not and block the exceeded input.
if (e.target.value.length > phoneNumberExample.length) return;
//Check input value is only formed with number or space.
const isNumeric = (val: string) => {
return val === "" || /^[0-9 ]+$/.test(val);
};
if (!isNumeric(e.target.value)) return;
let phoneNumberInput = e.target.value;
const lastWordIndex = phoneNumberInput.length;
//For erasing action, when the last word is space, erase that space
if (phoneNumberInput[lastWordIndex - 1] === " ") phoneNumberInput = phoneNumberInput.slice(0, lastWordIndex - 1);
// Add space for right location based on phone number example
if (phoneNumberExample[lastWordIndex] === " ") {
phoneNumberInput = phoneNumberInput.slice(0, lastWordIndex) + " " + phoneNumberInput.slice(lastWordIndex);
}
setPhoneNumber(phoneNumberInput);
}}
결국 모든 validation 관련 코드가 onChange
안으로 들어가게 되었다. 이게 좋은 방법일지는 모르겠지만 (추후에 코드리뷰를 받고, 고치게 되는 부분이 있다면 업데이트해야겠다) 지금으로선 디자인 가이드를 따라서 기술적으로 모든 케이스를 커버할 수 있는 방법이었다.
그리하여.. 하루를 거의 다 잡아먹은 결과물되시겠다. 사실 처음엔 이렇게 자세하게 적을 생각이 없었고 시행착오
부분까지만 간단하게 설명하려고 했었다. 하지만 전화번호 입력칸을 만들다보니 생각해야 할 것들이 점점 다양해졌고, 오랜만에 머리를 굴려 작성한 코드라 이왕 이렇게 된 김에 기록해두면 좋겠다 싶어서 끝까지 작성하게 되었다. 아직 자잘한 버그가 남아있어 손을 봐야하지만 큰 흐름엔 변화가 없을 것 같다.
[Html] Input 태그 Number 타입의 Maxlength 최대 자릿수 설정하기
html5 | input type number maxlength 설정 ( 모바일 ) / oninput, max, min
<input>
태그의 pattern 속성
핸드폰 번호 하이픈(-) 자동입력
html input pattern 정규표현식 모음
JavaScript에서 Sring이 숫자인지 확인
[javascript] 자주 사용하는 정규 표현식 (Regular Expression) 정리