0

I'm working with controlled input elements at work and I'm stuck.

Basically, I need to autofill some input elements in a form, but the problem is that I need to fill it in a way that simulates the user input (in this case, typing) in order to trigger the onChange function's logic. So, because of that. I need to emulate the typing behavior and not just set the value for the element.

Despite having searched for previous questions and reading docs about KeyboardEvent, I haven't been able to make this work.

Currently, I'm experimenting in a Codesandbox just for making things easier, but even with this simple environment, I can't manage to get this to work.

Here's the code and its Codesandbox link

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

export default function App() {
  const [state, setState] = useState();

  const inputRef = useRef();

  const event = new KeyboardEvent("keypress", { key: 99 });

  useEffect(() => {
    inputRef.current.dispatchEvent(event);
  }, [inputRef]);

  const onChange = (e) => {
    setState(e.target.value);
  };

  return (
    <div className="App">
      <h1>{state}</h1>
      <input
        type="text"
        id="name"
        onChange={onChange}
        ref={inputRef}
        value={state}
      />
    </div>
  );
}

Hopefully one of you guys could give me a hand with this.

Thanks for reading!

3
  • Is there any reason you can't just set the value and programmatically trigger the onChange function to get that effect? Commented Oct 15, 2021 at 17:24
  • @jnotelddim Hi! That could work too. Do you know how I could do that? Commented Oct 15, 2021 at 17:27
  • Sure, I'll add an answer with what I'm thinking of. Commented Oct 15, 2021 at 17:31

2 Answers 2

1

Related to the comments:

I think that it shouldn't be necessary to be dispatching a keypress event to get your special effect logic to run.

For example, you can use a useEffect which just runs on initial render to trigger whatever special logic you want -- and this way you can just have a regular initial value for the form state.

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

export default function App() {
  // In the useState call, you can initialize the value.
  const [state, setState] = useState("initial value");

  const specialEffectFunction = () => {
    // here's the code for the special effect you want to run on load
    console.log('this is the special onChange effect')
  }

  useEffect(() => {
    // This will trigger the special function which you want to run
    // when the app loads
    specialEffectFunction();
    // if it really HAS to be the `onChange` function that's called,
    // then you'll need to call that with a fake ChangeEvent.. but I don't
    // think that should be necessary...

  }, [])

  const onChange = (e) => {
    setState(e.target.value);
  };

  return (
    <div className="App">
      <h1>{state}</h1>
      <input
        type="text"
        id="name"
        onChange={onChange}
        value={state}
      />
    </div>
  );
}
Sign up to request clarification or add additional context in comments.

1 Comment

Sorry, I'm realizing I'm still not totally clear on the context of the special effect you're trying to get happening as the form initializes. Regardless, I don't think it should be necessary to try to "emulate" typing behaviour.
1

I couldn't fix the problem with Keyboard Event for my lack of knowledge about it, but I hope I managed to solve the problem of emulating a human autofill the input using the below code.


function AutoFillInput({ finalValue }: { finalValue: string }) {

  const [inputValue, setInputValue] = useState('');
  const [sliceStart, setSliceStart] = useState(0);

  const changeHandler = useCallback((event) => {
    setInputValue(event.target.value);
  }, []);


  useEffect(function handleFinalValueChange() {

    setInputValue('');

    if (sliceStart < finalValue.length)
      setSliceStart(x => x + 1);

  }, [finalValue]);


  useEffect(function handleSlice() {

    setInputValue(finalValue.slice(0, sliceStart));

    if (sliceStart < finalValue.length) {
      setTimeout(() => {
        setSliceStart(x => x + 1);
      }, 800);
    }

  }, [sliceStart]);



  return (
    <input
      value={inputValue}
      onChange={changeHandler}
      placeholder={'Auto fill input'}
    />
  )
}


function App() {

  return (
    <div >
      <AutoFillInput finalValue={'hello world'} />
    </div>
  );
}



export default App;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.