最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Trying to dispatch keypress event in React - Stack Overflow

programmeradmin1浏览0评论

I have a ponent with an input element and I would like to trigger a "tab" keypress event on that input element in order to jump to the next input element whenever a certain set of logic happens.

I have a ref on the first input element and I'm attempting to trigger the keypress event like so:

useEffect(() => {
  if (ref.current) {
    ref.current.focus();
    setTimeout(() => {
      ref.current.dispatchEvent(
        new KeyboardEvent("keypress", { key: "Tab" })
      );
    }, 3000);
  }
});

First I make sure to select the first input element with .focus(), then after 3 seconds I trigger pressing the tab key, expecting to see the focus move to the next field, but it does not seem to work.

It may seem like a strange example, but this is just a prototype. What I am actually planning to do is to trigger some code when I submit the first input field, that will fetch some rows with additional input fields and once that has been rendered I need to trigger the "tab" key. I would like to avoid attaching refs to these dynamically loaded input fields as I feel it adds a lot of overhead keeping track of the refs and passing them down, when all I need is to leverage the tab order and simulate a keypress to tab to the first dynamic loaded item once it has loaded. I'm ok with adding a single ref to the field you need to submit to populate the dynamic fields.

I noticed a few examples online calling .dispatchEvent() directly on the ref object, but if I try that I get an error telling that the function does not exist, so I call it on the current prop instead. Not sure if that has any relevance.

Here is a link to a prototype where the above code was taken from: =/src/App.js:149-441

I have a ponent with an input element and I would like to trigger a "tab" keypress event on that input element in order to jump to the next input element whenever a certain set of logic happens.

I have a ref on the first input element and I'm attempting to trigger the keypress event like so:

useEffect(() => {
  if (ref.current) {
    ref.current.focus();
    setTimeout(() => {
      ref.current.dispatchEvent(
        new KeyboardEvent("keypress", { key: "Tab" })
      );
    }, 3000);
  }
});

First I make sure to select the first input element with .focus(), then after 3 seconds I trigger pressing the tab key, expecting to see the focus move to the next field, but it does not seem to work.

It may seem like a strange example, but this is just a prototype. What I am actually planning to do is to trigger some code when I submit the first input field, that will fetch some rows with additional input fields and once that has been rendered I need to trigger the "tab" key. I would like to avoid attaching refs to these dynamically loaded input fields as I feel it adds a lot of overhead keeping track of the refs and passing them down, when all I need is to leverage the tab order and simulate a keypress to tab to the first dynamic loaded item once it has loaded. I'm ok with adding a single ref to the field you need to submit to populate the dynamic fields.

I noticed a few examples online calling .dispatchEvent() directly on the ref object, but if I try that I get an error telling that the function does not exist, so I call it on the current prop instead. Not sure if that has any relevance.

Here is a link to a prototype where the above code was taken from: https://codesandbox.io/s/wizardly-hopper-vrh4w?file=/src/App.js:149-441

Share Improve this question asked Aug 7, 2020 at 22:00 zkwskzkwsk 2,1366 gold badges31 silver badges35 bronze badges 2
  • 1 It appears this is not possible to do via javascript DOM events per stackoverflow./questions/32428993/… – devspeter Commented Aug 7, 2020 at 23:24
  • Unfortunately you seem to be right. See the note about manually firing events not triggering native browser actions: developer.mozilla/en-US/docs/Web/API/KeyboardEvent – zkwsk Commented Aug 8, 2020 at 22:04
Add a ment  | 

3 Answers 3

Reset to default 5

Per the answer I got in the ments it appears that you cannot trigger native browser behaviour (as a security feature) by emulating keystrokes (there's a note about 2/3 down the page): https://developer.mozilla/en-US/docs/Web/API/KeyboardEvent

Try it this way

new KeyboardEvent("keydown", { keyCode: "Tab", which: 9 })

Here's how I got the which https://keycode.info/

As pointed out by @funkylaundry, you can't trigger native browser actions by dispatching your own events for security reasons.

However, what you want to do can be achieved with the autofocus (HTML) / autoFocus (JSX) attribute, as shown below:

const App = () => {
  const [showExtraFields, setShowExtraFields] = React.useState(false);
  const [showMoreExtraFields, setShowMoreExtraFields] = React.useState(false);
  
  React.useEffect((e) => {
    setTimeout(() => {
      setShowExtraFields(true);
    }, 3000);
    
    setTimeout(() => {
      setShowExtraFields(false);
      setShowMoreExtraFields(true);
    }, 6000);
    
    setTimeout(() => {
      setShowExtraFields(true);
      setShowMoreExtraFields(true);
    }, 9000);
  }, []);

  return (
    <form>
      <input placeholder="Input 1" autoFocus />
      
      { showExtraFields && (<React.Fragment>
        <input placeholder="Input 2" autoFocus />
        <input placeholder="Input 3" />
        <input placeholder="Input 4" />
      </React.Fragment>) }
      
      { showMoreExtraFields && (<React.Fragment>
        <input placeholder="Input 5" autoFocus />
        <input placeholder="Input 6" />
        <input placeholder="Input 7" />
      </React.Fragment>) }
    </form>
  );
}

ReactDOM.render(<App />, document.querySelector('#app'));
body {
  font-family: monospace;
}

input {
  display: block;
  margin-bottom: 8px;
  font-family: monospace;
  padding: 8px;
  background: white;
  border: 2px solid black;
}
<script src="https://unpkg./[email protected]/umd/react.development.js"></script>
<script src="https://unpkg./[email protected]/umd/react-dom.development.js"></script>

<div id="app"></div>

Note how the focus goes Input 1 -> Input 2 -> Input 5 -> Input 2.

Basically, if there's more than one input with autoFocus on the page, the last element to be mounted gets it. That's why in the last update, when both groups of inputs are shown, the focus goes to Input 2, which has just been mounted, rather than Input 5, which es after Input 2 but was already present on the page.

发布评论

评论列表(0)

  1. 暂无评论