Nick
Nick

Reputation: 1541

Submitting form from parent component

I would like to create a form where the submit button is located in the header. I'm currently using react-hook-forms but am having difficulties being able to submit the form from a component that is in the layout the displays the form (or child). I've included an image that may help visualize what im talking about.

enter image description here

Is there a way I can pass that form data or handleSubmit from react-hook-form to to the header that would then run the onSubmit when clicked?

Upvotes: 11

Views: 17406

Answers (5)

Tgralak
Tgralak

Reputation: 147

You can set ref on form:

<form ref={formRef} onSubmit={handleSubmit}>

and then simulate onSubmit from any place:

formRef.current.requestSubmit();

This behaves as submit button click, without inserting unnecessary submit button: https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/requestSubmit

Upvotes: 7

Javier
Javier

Reputation: 518

Just create a ref in the parent component, send it to the child component and assign that ref to an invisible submit button.

Finally, in the onClick event of the parent submit button simply call submitRef.current.click()

// ./From.js
import React from 'react';
import { useForm } from 'react-hook-form';

// This is the child component with a ref received from the parent
// and assigned to an invisible submit button 
const Form = ({ submitRef }) => {
  const {register, setValue, getValues, ...other } = useForm();

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      ...
      <button ref={submitRef} type="submit" style={{ display: 'none' }} />
    </form>
  );  
}; 


export default Form;
// ./Parent.js
import React, { useRef } from 'react';
import Form from './Form'
 
const Parent = () => {
  const submitRef = useRef();

  return (
    <>
      <button onClick={() => submitRef.current.click()}>Submit</button>
      <Form submitRef={submitRef}/>
    </>
  );  
}; 
export default Parent;

Upvotes: 16

grijjLY
grijjLY

Reputation: 89

function handleForm(e) {
e.preventDefault()
// your code here
}

<button onClick={()=>{document.forms[0].submit()}} >Submit</button>

<form onSubmit={handleForm} >...</form>


For haters who dislike the answer:

const formRef=useRef();

function handleForm(e) {
e.preventDefault()
// your code here
}

<button onClick={()=>formRef.current.submit()} >Submit</button>

<form ref={formRef} onSubmit={handleForm} >...</form>

Upvotes: -4

coagmano
coagmano

Reputation: 5671

The simplest way to do this is by raising the form state to the closest parent between the two components, then you can pass the change and submit handlers down to the requisite components.

See https://reactjs.org/docs/lifting-state-up.html

In the case of react-hook-form that means calling useForm in that highest shared component and passing down the functions, ideally using composition instead of prop drilling

Upvotes: 0

PJMan0300
PJMan0300

Reputation: 76

You may want to investigate redux form and/or connect()

Example:

import React from 'react';
import { useForm } from 'react-hook-form';
import { connect } from 'react-redux';
 
const Form = ({ register, handleSubmit }) => {
  const methods = useForm();

  return (
    <form onSubmit={handleSubmit(register)}>...</form>
  );  
}; 

const mapDispatchToProps = dispatch => ({
  register: (data) => dispatch(register(data))
});
 
export default connect(null, mapDispatchToProps)(Form);

import React from 'react';
import { useForm } from 'react-hook-form';
import { connect } from 'react-redux';
 
const Form = ({ register, handleSubmit }) => {
  const methods = useForm();

  return (
    <form onSubmit={handleSubmit(register)}>...</form>
  );  
}; 
export default connect(null, mapDispatchToProps)(Form);

Upvotes: -1

Related Questions