javascripthtmlreactjsonkeydownselection-api

Event “OnKeyDown” fires only once in react app


Hello everyone. I am new to web dev. I just can't understand the problem. My task is to change the parts of the input (day and month) using a combination of ctr + ArrowUp (increase) and ctr + ArrowDown (decreases). Also the variable part is highlighted - this is achieved by tracking the position of the cursor (selectionStart). The code works, but for some reason “OnKeyDown” is executed only once and other button presses have no effect. Why it happens? How do I make the event “OnKeyDown” work on every combination of buttons pressed?

SANDBOX SNIPPET

My Code


import React, { useState, useEffect, useRef } from "react";
import styles from "./DataInput.module.css";

const cur_date = new Date();

const DataInput = () => {
  const inputEl = useRef();
  const [selection, setSelection] = useState();
  const [currentDate, newCurrentDate] = useState();

  const date_format = cur_date
    .toLocaleString()
    .replaceAll(".", "/")
    .replace(",", "");

  const [value, setValue] = useState(date_format);

  useEffect(() => {
    if (!selection) return; // prevent running on start
    const { start, end } = selection;
    inputEl.current.focus();
    inputEl.current.setSelectionRange(start, end);
  }, [selection]);

  const keyHandler = (e) => {
    if (e.ctrlKey && e.key === "ArrowUp") {
      e.preventDefault();
      if (
        inputEl.current.selectionStart > 0 &&
        inputEl.current.selectionStart < 2
      ) {
        setSelection({ start: 0, end: 2 });
        const newDay = cur_date.setDate(cur_date.getDate() + 1);
        setValue(
          new Date(newDay)
            .toLocaleString()
            .replaceAll(".", "/")
            .replace(",", "")
        );
      }
      if (
        inputEl.current.selectionStart > 3 &&
        inputEl.current.selectionStart < 5
      ) {
        setSelection({ start: 3, end: 5 });
        const newMonth = cur_date.setMonth(cur_date.getMonth() + 1);
        setValue(
          new Date(newMonth)
            .toLocaleString()
            .replaceAll(".", "/")
            .replace(",", "")
        );
      }
    }
    if (e.ctrlKey && e.key === "ArrowDown") {
      e.preventDefault();
      if (
        inputEl.current.selectionStart > 0 &&
        inputEl.current.selectionStart < 2
      ) {
        setSelection({ start: 0, end: 2 });
        let newDate = cur_date.setDate(cur_date.getDate() - 1);
        setValue(
          new Date(newDate)
            .toLocaleString()
            .replaceAll(".", "/")
            .replace(",", "")
        );
      }
      if (
        inputEl.current.selectionStart > 3 &&
        inputEl.current.selectionStart < 5
      ) {
        setSelection({ start: 3, end: 5 });
        const newMonth = cur_date.setMonth(cur_date.getMonth() - 1);
        setValue(
          new Date(newMonth)
            .toLocaleString()
            .replaceAll(".", "/")
            .replace(",", "")
        );
      }
    }
  };

  const changeHandler = (e) => {
    setValue(e.target.value);
  };

  return (
    <div className={styles.main}>
      <h1> Frontend Task</h1>
      <p id="name">Abramov David</p>
      <input
        ref={inputEl}
        value={value}
        onChange={changeHandler}
        onKeyDown={keyHandler}
      />
    </div>
  );
};

export default DataInput;


Solution

  • I think it's just an issue with some if statements using incorrect index checking and duplication of inputEl.current.selectionStart.

    For example:

    if (
            inputEl.current.selectionStart > 0 &&
            inputEl.current.selectionStart < 2
       )
    

    Should be something like:

    if (
            inputEl.current.selectionStart >= 0 &&
            inputEl.current.selectionEnd <= 2
       )