기획에서 사용자가 가진 포인트에 대해 100원 단위로만 입력이 되도록 입력을 강제하는 Input 을 구현해달라는 요청을 받았다. 이 때에 입력될 수 있는 최대값은 사용자가 가진 포인트의 100단위로 환산된 값이어야 한다. (심지어, 상황이 여의치 않아 html 구현 후 해당 string을 webview에 심어서 랜더링하는 중)
아무 생각 없이 입력값의 *100을 한 다음에 기존 값에 더해주면 되겠다고 생각했던 나는 그렇게 구현했다가 입력값이 "100123121212121212..." 라는 식으로 어처구니 없게 늘어나는 것을 보고 단단히 잘못 생각했다는 것을 알게 되었다.
생각보다 쉽게 해결할 수 있을거라고 생각했던 문제에 대해서 역시 쉽게 생각하면 답이 안나온다는 것을 알았다.
문제의 이유는 의외로 간단했다.
이게 계속 이어지면 110022003300... 이런 식이 되어서 문제다.
즉, 현재 문제는 keyPressed되는 값과 input의 value가 서로 다르다는 것을 인지하지 못하고 벌어진 일이었다.
html에서 해당 과정을 어떻게 구현할지 고민을 좀 해보다가, focus가 사라지면 계산되서 넣는 방식으로 할까 생각했는데 그건 좀 유저경험에 좋지 않아보였다.
그래서 역시 원래 의도대로 입력을 하면 곧바로 그것에 100이 곱해진 값이 치환되어서 들어가야 했다.
이 문제점에 대해서 조금 더 생각해보면 아래와 같다.
이렇게 써놓고 보니 문제를 확연하게 알 수 있었다.
결국, 사용자가 입력된 값을 기록하고 있어야 한다는 점이 핵심이었다.
다른 UI적 코드 포함하여 결과적인 script내용은 아래와 같다.
<script>
//! VARIABLES
const POINT = 1531 // 보유포인트 예시
// 보유 포인트 100원 단위로 환산
const TRANSFORMEDPOINT = valuePerHundered(POINT)
//! FUNCTIONS
function valuePerHundered(value) {
return Math.floor(value / 100) * 100
}
function setAllPoint() {
pointInput.value = TRANSFORMEDPOINT
point = String(TRANSFORMEDPOINT / 100)
}
function allPointUseBtnHanlder() {
const pointInput = document.getElementById('point-value');
setAllPoint()
}
function toggleDropdown(elementKeyword) {
const arrow = document.getElementById(`${elementKeyword}-arrow`);
const content = document.getElementById(`${elementKeyword}-content`);
arrow.classList.toggle('closed');
content.classList.toggle('closed');
}
function isNumberOrBackPressed(key) {
if (typeof +key === 'number' || key === null) return true
return false
}
let point = null; //입력한 keyPress 값을 기록하는 부분.
const pointInput = document.getElementById('point-value');
pointInput.addEventListener('keydown', (e) => {
const regex = /^\d+$/
if (e.key !== "Backspace" && !regex.test(e.key)) { // e를 숫자로 인식하기 때문에, 막아야 함.
e.preventDefault();
}
}
})
pointInput.addEventListener('input', (e) => {
const keyPressed = e.data; //키보드 값 = e.data
if (isNumberOrBackPressed(keyPressed)) {
//1. 키 입력에 따라 기록되었던 포인트를 변경한다.
if (keyPressed === null) { // null === backspace
point = point.slice(0, -1);
} else {
point = String(+point || "") + e.data
}
//2. 변경된 키 값이 존재하지 않으면, null처리하여 placeholder가 노출되도록 수정한다.
if (!point) {
point = null;
pointInput.value = null;
return
}
//3. 그게 아니라면 100을 곱해본 후, 보유 포인트가 넘는 지 안넘는 지 확인해서 적절한 값을 리턴한다.
const viewValue = point * 100;
if (viewValue > TRANSFORMEDPOINT) {
setAllPoint()
} else {
pointInput.value = viewValue;
}
}
})
</script>