24

I've two react events:

  1. Form submit event

    sendMessage: function(event){
        console.log(event);
        event.preventDefault();
    },
    
  2. keyPress Event

    textareaKeypress: function(event){
        if (event.which == 13 && !event.shiftKey){
            document.getElementById('messagebox').submit();
        }
    },
    

but the reactJS is not capturing the form submit triggered by textareaKeypress. How can I call the sendMessage from textareaKeypress with proper event?

4
  • My question is not about why this code isn't working, the question is about how to implement form submit trigger which can be catched by reactjs events. Commented Mar 6, 2015 at 18:22
  • 3
    I think you misunderstood my comment. I'm only talking about the formatting of your question, not your code/problem. You used "stack snippets" in your question, which allow us to directly run code on Stack Overflow, by adding big "run code snippet" buttons (see stackoverflow.com/revisions/28904875/1). But if your code examples are not excutable on their own, there is no need to use them. It will just clutter your question with those buttons. Commented Mar 6, 2015 at 18:23
  • i.e. Try using a Code Sample (curly braces in message editor) instead of Code Snippets (page with brackets icon). Commented Mar 6, 2015 at 18:25
  • 1
    @FelixKling ohh, sorry, totally misunderstood that. SeanO Thanks. I'll keep remember that from next time Commented Mar 6, 2015 at 18:27

4 Answers 4

32

I learned something new today: this is just how the DOM works.

From the MDN site:

The form's onsubmit event handler (for example, onsubmit="return false;") will not be triggered when invoking this method from Gecko-based applications. In general, it is not guaranteed to be invoked by HTML user agents.

According to the HTML spec:

The submit() method, when invoked, must submit the form element from the form element itself, with the submitted from submit() method flag set.

followed by (section 4.10.22.3)

If the submitted from submit() method flag is not set, then fire a simple event that bubbles and is cancelable named submit, at form.

So, the event is not fired if the submit() method flag is set.


I was able to get the behavior you (and I) were expecting via the following code (JSFiddle example):

<form onSubmit={this.handleSubmit} ref="form">
  <textarea onKeyPress={this.handleKeyPress} />
</form>

// ...

this.refs.form.getDOMNode().dispatchEvent(new Event("submit"));

(You'll need more verbose code in IE.)

jQuery's $(form).submit() delegates to $(form).trigger("submit"), so I expect it's a similar workaround.

Sign up to request clarification or add additional context in comments.

4 Comments

Just wanted to say thanks for your answer. Had a hard time finding it (was trying to do something similar with auto-submitting a form when a checkbox was clicked), but this solved my problem.
Use this.refs.form.submit(); instead of this.refs.form.getDOMNode().dispatchEvent(new Event("submit"));
@frevib As stated in both the question and this answer, submit() doesn't trigger React's submit event, thus the workaround
If above does not work for anyone then try this - ReactDOM.findDOMNode(this.form).dispatchEvent(new Event("submit")); And import ReactDOM from 'react-dom';
16

New method (24.08.2022)

Form element now has a requestSubmit() method, which would trigger submit event by itself without workarounds, as stated in submit() MDN docs:

The HTMLFormElement.submit() method submits a given <form>.

This method is similar, but not identical to, activating a form's submit <button>. When invoking this method directly, however:

The HTMLFormElement.requestSubmit() method is identical to activating a form's submit <button> and does not have these differences.

However, this method is not supported well enough on IE and Safari 15.6. As of 02.09.2022, this is about 76.49% global usage. If you need a more browser-compatible solution, keep reading until the end.

No need to use refs

Every answer I've yet seen uses refs when you actually don't need them. Most (if not all) of the form controls have a reference to a parent form in their form property:

textarea.form.requestSubmit();

Just make sure to attach a handler on one of the form controls, for example: <button>, <input>, <textarea>, <select>, <option>.

With all that said, you can write your handlers like that:

<form onSubmit={this.sendMessage}>
    <textarea onKeyPress={this.textareaKeypress}/>
</form>
sendMessage: function(event) {
    console.log(event);
    event.preventDefault();
},

textareaKeypress: function(event) {
    if (event.which == 13 && !event.shiftKey) {
        event.target.form.requestSubmit();
    }
},

Or if you care about browser compatibility, dispatch an event manually (thanks to Karol Dabrowski answer):

textareaKeypress: function(event) {
    if (event.which == 13 && !event.shiftKey) {
        event.target.form.dispatchEvent(new Event('submit', { cancelable: true, bubbles: true }));
    }
},

1 Comment

this is ace, thanks @Vasiliy Artamonov, for anyone wanting to add types to this, see my answer which extends upon this: stackoverflow.com/a/74558120/827129
7

Expanding on @VasiliyArtamonov's answer, here's how I got it working with Typescript:

const onKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>): void => {
  const commandKeyPressed = e.metaKey;
  const enterKeyPressed = e.key === "Enter";
  if (commandKeyPressed && enterKeyPressed) e.currentTarget.form?.requestSubmit();
};

Updated to include the tweak in @VasiliyArtamonov's comment below.

2 Comments

For avoiding issues with TypeScript, you have to use event.currentTarget instead of event.target. That way you can get rid of type assertion (as ...). The element inside currentTarget is where the handler is attached; the element inside target is the one that triggered the event, which is not always the same as currentTarget. Comparison of Event Targets.
Thanks @VasiliyArtamonov, I've gone ahead and updated my answer to reflect that.
3

It's your component, so you don't need to worry about passing actual events around. You have some event handlers, and then you have the actual action.

sendMessage: function(){
    console.log('message:', this.state.message);
},
handleFormSubmit: function(event){
    event.preventDefault();
    this.sendMessage();
},
handleTextareaKeypress: function(event){
    if (event.which == 13 && !event.shiftKey){
        this.sendMessage();
    }
}

1 Comment

This is the wrong answer. Cause I'm working with some thirdparty module and there are exist inner onSubmit handler. If I trigger form.submit() manually this handler won't be triggered.

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.