[기능구현] 100단위 입력 강제하기

devAnderson·2023년 3월 30일
0

Error Handling

목록 보기
9/12

💭 1. 어떤 상황이었냐면,

기획에서 사용자가 가진 포인트에 대해 100원 단위로만 입력이 되도록 입력을 강제하는 Input 을 구현해달라는 요청을 받았다. 이 때에 입력될 수 있는 최대값은 사용자가 가진 포인트의 100단위로 환산된 값이어야 한다. (심지어, 상황이 여의치 않아 html 구현 후 해당 string을 webview에 심어서 랜더링하는 중)

아무 생각 없이 입력값의 *100을 한 다음에 기존 값에 더해주면 되겠다고 생각했던 나는 그렇게 구현했다가 입력값이 "100123121212121212..." 라는 식으로 어처구니 없게 늘어나는 것을 보고 단단히 잘못 생각했다는 것을 알게 되었다.

생각보다 쉽게 해결할 수 있을거라고 생각했던 문제에 대해서 역시 쉽게 생각하면 답이 안나온다는 것을 알았다.

문제의 이유는 의외로 간단했다.

  1. 사용자는 key press를 통해 "1", "2," 와 같은 하나의 단일값을 입력하고 있는데
  2. input 태그 내부에 입력되는 값은 해당 입력 값들이 텍스트 형태로 더해지며 차례로 나열되는 중이다.
  3. 만약 단순하게 입력값에 대해서 * 100을 하고 더해줄 경우, 예를 들어 첫 입력이 1이면 해당 inputTag에 1이 들어가고, 거기에 pressed된 키 "1"에 100이 자동 타입변환과 함께 곱해져서 string인 1에 더해지게 된다("1100")


이게 계속 이어지면 110022003300... 이런 식이 되어서 문제다.

즉, 현재 문제는 keyPressed되는 값과 input의 value가 서로 다르다는 것을 인지하지 못하고 벌어진 일이었다.

💭 2. 그래서 해결방법은,

html에서 해당 과정을 어떻게 구현할지 고민을 좀 해보다가, focus가 사라지면 계산되서 넣는 방식으로 할까 생각했는데 그건 좀 유저경험에 좋지 않아보였다.

그래서 역시 원래 의도대로 입력을 하면 곧바로 그것에 100이 곱해진 값이 치환되어서 들어가야 했다.

이 문제점에 대해서 조금 더 생각해보면 아래와 같다.

  1. 사용자가 입력하는 keyPressed 값은 따로 존재해야 한다.
  2. 해당 값에 대해서 100이 곱해진 값이 view로 보여야 한다.
  3. 추가적으로, 사용자의 입력값이 해당 보유한 포인트보다 높을 경우, 보유한 포인트값의 100단위 치환값을 보여줘야 하고
  4. 그것이 아니라면 현재 입력된 keyPressed값의 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>
profile
자라나라 프론트엔드 개발새싹!

0개의 댓글