17

I have a form.

I try to submit this form from a different function.

To do so I created a ref. This ref, when printed, has the correct HTML Node and this node also has an submit method. When this submit method is called (formNode.submit()) the form get's submitted, but the onSubmit handler is never triggered.

Why?

Here is a simplified example which shows the same behavior.

class Form extends React.Component {
  constructor() {
    super();

    this.form = React.createRef();
  }

  render() {
    return (
      <div onClick={() => this.form.submit()}>
        Click me!
        <form
          onSubmit={e => console.log(e)}
          ref={f => (this.form = f)}
        />
      </div>
    );
  }
}

https://codesandbox.io/s/vm8pkmony

SlootSantos
  • 363
  • 1
  • 2
  • 10

6 Answers6

28

Starting from React 17 you have to add cancelable and bubbles properties to your event. Otherwise, the solution from the accepted answer won't work. It's caused by some changes in event delegation.

this.form.dispatchEvent(
    new Event("submit", { cancelable: true, bubbles: true })
);
Karol Dabrowski
  • 1,190
  • 1
  • 8
  • 18
18

For your specific use case, you'll have to fire the submit event of the form using dispatchEvent.

this.form.dispatchEvent(new Event("submit"));
br0k3n c0d3
  • 196
  • 2
3

When you call the form's submit function, the submit event is not fired.

This behaviour is intended because we're assuming that if you called submit directly you already validated your form.

Ramon Balthazar
  • 3,907
  • 3
  • 25
  • 34
3

It's an old question but we can do something like this;

As Ramon Balthazar mentioned above;

When you call the form's submit function, the submit event is not fired.

To solve this problem, we can create hidden button and add reference to it, than we can click that button with ref, it will submit the form and trigger submit event;

import { useRef } from 'react'

export default function Form(props) {
    const hiddenButtonRef = useRef(null)

    return (
        <>
            <form onSubmit={(e) => console.log(e)}>
                <input type="submit" style={{ display: 'none' }} ref={hiddenButtonRef} />
            </form>

            <div onClick={() => hiddenButtonRef.current.click()}>Click me!</div>
        </>
    )
}
Closery
  • 828
  • 9
  • 14
  • OP said "I try to submit this form from a different function." - so the question is how to programatically submit the form AND trigger the onSubmit. – Andrew Apr 06 '22 at 13:02
  • This approach worked for me! Note that, for TypeScript, I needed: `const hiddenButtonRef = useRef(null)` – Chris Livdahl Sep 09 '22 at 01:44
2

UPDATED solution currently I use formRef.current.requestSubmit()

  const formRef = useRef<HTMLFormElement>(null);


  const onClickCheckout = () => {
    if (formRef.current) {
      formRef.current.scrollIntoView({ block: "nearest", behavior: "smooth" });
      formRef.current.requestSubmit();
    }
  };
`
1

For people in 2021 using functional component:

You have to include a <button> inside of the form, and there is no need to add other props to trigger the onSubmit event of <form>!

For example:

    <form ref={formRef} onSubmit={handleSubmit}>
        <div style={{display: "flex", flexDirection: "column"}}>
            <h1 style={{ alignSelf: "center" }}>Import Your Space</h1>
            <InputText label="space-id" ref={spaceIdRef}
                       init={spaceId} onChange={value => setSpaceId(value)}/>
            <InputText label="map-id" ref={mapIdRef}
                       init={mapId} onChange={value => setMapId(value)}/>
            <InputTextArea label="rooms" ref={roomsRef}
                           init={rooms} onChange={value => setRooms(value)}/>
            <button style={{background: "lightgreen", alignSelf: "flex-end"}}>
                Start Discrimination</button>
        </div>
    </form>
NeoZoom.lua
  • 2,269
  • 4
  • 30
  • 64