skip to Main Content

I have the next scenario in my react js appplication:

import { useEffect, useState } from "react";
import "./styles.css";

const inputDefautValues = ["first val", "second value"];

const Input = ({ setIsopen, val }) => {
  const [value, setValue] = useState("");

  useEffect(() => {
    setValue(val);
  }, [val]);
  return (
    <input
      value={value}
      onChange={(e) => {
        setIsopen(e.target.value === "?");
        setValue(e.target.value);
      }}
      onBlur={(e) => e.target.value === "?" && setValue(val)}
    />
  );
};

const Modal = ({ data }) => {
  return (
    <div>
      Modal data: <input />
    </div>
  );
};

export default function App() {
  const [isOpen, setIsopen] = useState(false);
  return (
    <div className="App">
      {inputDefautValues.map((val, i) => (
        <Input val={val} key={i} setIsopen={setIsopen} />
      ))}
      {isOpen && <Modal />}
    </div>
  );
}

The idea is next: User type ? in one of the input and then typing something in the second one the previous value should return and ? dissapears (the flow is working at the moment). If user type ? in one of the input also a modal window appears, but clicking on the input from that modal also restore the initial value of the input making ? to dissapear. The expected behaviour is when user type ? and then click on the modal input the ? sign should stay in the first input, if user type ? in one of these 2 inputs ant then click on next input the ? sign should dissapear and initial value should appear (like is now).
Question: How to prevent input to remove ? sing when clicking on the modal input taking into account the scenario above?

demo: https://codesandbox.io/p/sandbox/loving-tereshkova-fsc7lz?file=%2Fsrc%2FApp.js

2

Answers


  1. Have you tried delayed the execution of the onBlur handler using setTimeout?

    import { useEffect, useState } from "react";
    import "./styles.css";
    
    const inputDefautValues = ["first val", "second value"];
    
    const Input = ({ setIsOpen, val, modalInputRef }) => {
      const [value, setValue] = useState("");
    
      useEffect(() => {
        setValue(val);
      }, [val]);
    
      const handleBlur = (e) => {
        setTimeout(() => {
          // Check if the currently focused element is the modal input
          if (document.activeElement !== modalInputRef.current) {
            if (e.target.value === "?") {
              setValue(val);
            }
          }
        }, 0); // Delay to allow the document to update the activeElement
      };
    
      return (
        <input
          value={value}
          onChange={(e) => {
            setIsOpen(e.target.value === "?");
            setValue(e.target.value);
          }}
          onBlur={handleBlur}
        />
      );
    };
    
    const Modal = ({ modalInputRef }) => {
      return (
        <div>
          Modal data: <input ref={modalInputRef} />
        </div>
      );
    };
    
    export default function App() {
      const [isOpen, setIsOpen] = useState(false);
      const modalInputRef = useState(useRef(null))[0]; // Using useRef to reference the modal input
    
      return (
        <div className="App">
          {inputDefautValues.map((val, i) => (
            <Input val={val} key={i} setIsOpen={setIsOpen} modalInputRef={modalInputRef} />
          ))}
          {isOpen && <Modal modalInputRef={modalInputRef} />}
        </div>
      );
    }
    
    Login or Signup to reply.
  2. I think the requirements are not very clear, and in my opinion there are things that could be improved here, but i’m not very sure why you want it this way, but here it is anyway. The easiest solution I could think of is to add unique classes to the first two inputs (you can change them to ids, or whatever), and then when onBlur happens, we can check which element causes the onBlur event to occur, if it’s the second input, then we reset the first input, if it’s anything else, we keep the "?". Basically change the onBlur code to this:

    ...
          onBlur={(e) => {
            if (
              e?.relatedTarget?.className?.startsWith("input") &&
              e.target.value === "?"
            ) {
              setValue(val);
            }
          }}
    ...
    

    The relatedTarget is the element in which we click at that makes the onBlur occurs. And we also need to add classNames to the inputs:

    const className = `input${i}`;
    ...
    classNames={className}
    

    Here is the forked sandbox:

    Edit loving-tereshkova-forked-s2dktk

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search