Hello!
I've spent way too much time now on this, I think I may be missing something. How should I submit form from a parent component? E.g. a
<Parent>
<FormWithReduxForm ref="form" />
<Button onClick={this.refs.form.handleSubmit} />
</Parent>
I did simplify, but I can't seem to get this.refs.form from parent. Please, advice.
No, you can't do that. handleSubmit does not get assigned to the component instance. You can't even do a this.handleSubmit = this.props.handleSubmit in your form component constructor, because it's wrapped in several higher order components, so your this.refs.form is _not_ going to be your internally wrapped component instance. Calling instance methods on child components is generally frowned upon in the React community from what I can tell.
I'd recommend something like what I described in #179.
@erikras Thank You for that link, a good example there. However, being able to have some action that you can call to trigger submit of a for by form name or key would be great! Consider example where you have form loaded dynamically based on form scheme you get from server - I called it SimpleFormFactory, which was decorated with redux-form, and this form is reused like
<SimpleForm scheme={scheme} fileds={fields} />
but this form does not render own controls to submit - those are handled by parent,
I'm not really sure what to suggest, other than just putting the submit button inside the SimpleForm component.
So, how about adding a getWrappedInstance() method to ReduxFormConnector, passing the wrapped form instance through to the parent/owner component? I know, this shouldn't be overused, but there are places where it is very useful IMHO. There's a reason redux provides the getWrappedInstance() method on the connect wrapper after all.
Given there's access to the form component instance from a parent, we will be able implement submitting from outside:
@reduxForm({ [some def] })
class MyForm extends Component {
...
doSubmit() {
this.props.handleSubmit();
}
}
And then in the parent:
class MyComp extends Component {
render() {
return (
<div>
<MyForm ref="myform" />
<button onClick={ this.handleClick }>Submit me </button>
</div>
);
}
handleClick = () => {
this.refs.myform.getWrappedInstance().doSubmit();
}
}
:+1: on that, getWrappedInstance() would be very useful. For me it is a situation that I have a modal and the form is inside of the "content" part of the modal while submit button should be a modal action button, so it is outside of the form. And I cannot wrap the whole modal in <form> because it breaks styles.
I have a similar problem.
I need to submit the current form when the user click a link inside a top navigation menu.
I have no clues on how to do this with redux-form, or even if it's possible.
@yleclanche I have another ugly solution, saving the handleSubmit in store.
// SimpleForm.js
class SimpleForm extends Component {
componentDidUpdate() {
// onSubmit might change, so saveSubmitToStore should be triggered in componentDidUpdate
this.props.saveSubmitToStore(this.props.handleSubmit);
}
}
export default reduxForm({
form: 'simple',
fields,
})(SimpleForm);
// formUtil.js action creator
case SAVE_SUBMIT_TO_STORE:
return Object.assign({}, state, {
handleSubmit: action.handleSubmit
});
// call handleSubmit anywhere
store.formUtil.handleSubmit();
Running into same issue. I think consistency by providing a getWrappedInstance() method makes sense.
So what is the most recommended stable workaround at the moment?
And I'd really like to see a proper solution provided by redux-form :)
I had to do this using react native and ended up creating an eventEmiter in
the parent component and passing that to the child and the child listened
to a 'submit' event which would trigger the handleSubmit function.
Works well.
On 22 December 2015 at 02:13, flosse [email protected] wrote:
So what is the most recommended workaround at the moment?
And I'd really like to see a proper solution provided by redux-form :)—
Reply to this email directly or view it on GitHub
https://github.com/erikras/redux-form/issues/202#issuecomment-166326992.
I could really use something like this too for reasons similar to those mentioned.
I haven't thought through this deeply so there are probably good reasons not to do this, but I would prefer to see something like this:
import { submitForm } from 'redux-form';
submitForm('contactForm');
The primary point being that I wouldn't need to deal with accessing the particular "wrapped" component.
is there any progress?
I also need getWrappedComponent.. And not for submitting the form. I need to call one of component methods that opens form in a modal. Consider please providing this method as it is needed in many scenarios. And like others said it would be consistent with @connect from react-redux.
Also would like to see this functionality for the same reason as @eXtreme. Currently, it seems like I will have to put the modal buttons inside the form itself.
Access to the wrapped instance seems like the best solution at the moment.
My components are laid out as follows:
<Modal>
<Modal.Body>
<ReduxFormComponent/>
</Modal.Body>
<Modal.Footer>
<Button>Submit</Button>
<Button>Close</Button>
</Modal.Footer>
</Modal>
@erikras, would you entertain a PR for this functionality? Seems like quite a few people could use it. I have it working in a fork, but the code isn't the prettiest so it could use some touching up.
Come and get it, folks! v4.2.0
Looks perfect, thanks @erikras!
AWESOME thank you @erikras

Nice work with this lib @erikras. Thanks!
Thank you. This is a step in the right direction, but I'd still really like to see getWrappedInstance() (in my case, to help with testing things unrelated to redux-form) and:
import { submitForm } from 'redux-form';
submitForm('contactForm');
so I don't need access to the view component in order to submit the form.
Would you be amenable to either of those? If so, would you like separate issues opened?
Not a fan of this implementation...
React doesn't even recommend string refs:
https://facebook.github.io/react/docs/more-about-refs.html#the-ref-string-attribute
Why isn't it possible to mount a child form at a specific location. A child form will by default submit when the parent is submitted and attach it's values to the mount-point of the parent?
Yes, access to the wrapped component would be useful, or exposure of internal props such as submitting etc so that the external submit button can know whether it should be enabled/disabled, etc.
@DrMeers, v6 has a fairly extensive Instance API.
Thanks @erikras . Would it be worth explicitly exposing submitting as well for this use-case?
Would something like this be possible? I am working on a page that is similar to this:
http://redux-form.com/5.2.5/#/examples/multirecord?_k=ib8ndx
I want to add a "Submit" button to the parent that would submit all of the forms and wait for the responses before performing the next action.
In each child form I am returning a promise to handleSubmit. Would there be anyway to get that promise in the parent?
@erikras Can you provide an example use of the instance API ? I'm trying this without success :
const ContactForm = reduxForm({
form: 'contact-form'
})(SimpleForm); // form component
export const ModalWindow = ({ close }) => {
const form = <ContactForm />;
return (
<Modal show>
<Modal.Body>
{form}
</Modal.Body>
<Modal.Footer>
<Button onClick={close}>Cancel</Button>
<Button onClick={form.submit}>Validate</Button>
</Modal.Footer>
</Modal>
);
};
(I'm on 6.0.0-rc.3)
This is how I did it ...
My modal component
import React, { Component, PropTypes } from 'react'
import { connect } from 'react-apollo'
import { SubmissionError } from 'redux-form'
import { Layout, Header, Content, Footer, Button, IconButton } from 'react-mdl'
import Form from './Form'
class AddSalon extends Component {
onSubmit = (fields) => {
console.log('submit', fields)
}
onClick = () => {
this.refs.form.getWrappedInstance().submit()
}
render() {
const { close } = this.props
return (
<Layout fixedHeader>
<Header title={'Add Salon'}>
<IconButton name={'clear'} onClick={close}/>
</Header>
<Content>
<Form ref={'form'} initialValues={add} onSubmit={this.onSubmit}/>
</Content>
<Footer size={'mini'}>
<Button raised ripple onClick={this.onClick}>Save</Button>
</Footer>
</Layout>
)
}
}
function mapQueriesToProps({ ownProps, state }) {
return {}
}
function mapMutationsToProps({ ownProps, state }) {
return {}
}
function mapStateToProps(state, ownProps) {
return {}
}
export default connect({
mapQueriesToProps,
mapMutationsToProps,
mapStateToProps,
})(AddSalon)
My form component
import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux'
import { reduxForm, Field } from 'redux-form'
class Form extends Component {
render() {
const { handleSubmit } = this.props
return (
<form onSubmit={handleSubmit}>
<Field name="title" label="Title" component="input"/>
</form>
)
}
}
function validate(values) {
const errors = {}
if (!values.title) {
errors.title = 'Required'
}
return errors
}
function mapStateToProps(state, ownProps) {
return {}
}
Form = reduxForm({
form: 'salon',
validate,
})(Form)
export default connect(mapStateToProps, null, null, { withRef: true })(Form)
Notice the usage of { withRef: true }
In my case I have to do some seriously janky business to get access to the instance (let alone the handleSubmit prop of that instance which is what I really want). I'm really curious why we can't access form submission API via something like I mentioned in https://github.com/erikras/redux-form/issues/202#issuecomment-170261046. Is there a technical constraint? A design decision?
import { submitForm } from 'redux-form';
submitForm('contactForm');
I too would really love to see this implemented. I'm calling the form not from a parent, but another sibling component (from a header), so there is no way to elegantly trigger the form submission.
That said, there is another way to trigger it with simple js:
window.document.querySelector('[type="submit').click();
Maybe my message not consist answer on topic, but this artificial problem for you application logic. You can send popup logic (on submit) as callback to _handleSubmit_ and pass as param function for close event.
Other cases - visualization.
Example parent component:
import React, { Component, PropTypes } from 'react';
import { connect } from 'react-apollo';
import { SubmissionError } from 'redux-form';
import { Layout, Header, Content, Footer, Button, IconButton } from 'react-mdl';
// actions
import * as actionsPopup from '../../utils/actions';
// components
import Form from './Form';
class AddUser extends Component {
constructor(prop) {
super(prop);
this.formSubmitHandler = this.formSubmitHandler.bind(this);
this.closeModalHandler = this.closeModalHandler.bind(this);
}
formSubmitHandler(values) {
// any your code ...
this.props.actionsPopup.hide();
}
closeModalHandler {
// close modal window
this.props.actionsPopup.hide();
}
render() {
const { close } = this.props
return (
<Layout fixedHeader>
<Header title={'Add User'}>
<IconButton name={'clear'} onClick={close}/>
</Header>
<Content>
<Form
formSubmitHandler = {this.formSubmitHandler}
onClose = {this.closeModalHandler}
/>
</Content>
</Layout>
)
}
}
function mapStateToProps() {
return {};
}
function mapDispatchToProps(dispatch) {
return {
actionsPopup: bindActionCreators(actionsPopup, dispatch)
};
}
export default connect({
mapStateToProps,
mapDispatchToProps
})(AddUser);
Example form:
import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { reduxForm, Field } from 'redux-form';
class Form extends Component {
render() {
const { handleSubmit, formSubmitHandler, closeModalHandler } = this.props
return (
<form onSubmit={handleSubmit(formSubmitHandler)}>
<Field name="title" label="Title" component="input"/>
<button onClick={closeModalHandler} type="button">Cancel</button>
</form>
);
}
}
function validate(values) {
const errors = {}
if (!values.title) {
errors.title = 'Required'
}
return errors;
}
function mapStateToProps(state, ownProps) {
return {};
}
Form = reduxForm({
form: 'salon',
validate,
})(Form)
export default connect(mapStateToProps, null, null, { withRef: true })(Form);
as @markoshust said :raised_hand_with_fingers_splayed:
import { submitForm } from 'redux-form';
submitForm('contactForm');
that would be awesome!
@aludvigsen isn't it resolved in 6.2.0? http://redux-form.com/6.2.0/examples/remoteSubmit/
@eXtreme absolutely!! 😂 New version - perfect! Looks good. thanks!
awesomesauce..... this ticket can be closed
update: oh, it is :)
How doe this work with the Wizard Form example? I am trying to get the next buttons to validate & not progress forward if validation fails.
Similar to above examples the action buttons are located in a modal footer instead of inside the actual form decorator component.
@StevenHensgen did you get this working?
@SamMatthewsIsACommonName
I did get this working. My approach was to make the "prev" / "next" buttons to be disabled based on both sync & async validation status (I had to manually connect to my redux form to get this for some reason I cannot remember) & then only use the remote dispatch submit function when no errors exist on the page.
Great idea thanks. I managed to find a way by importing the store and calling dispatch of an action which progressed the wizard from the submit function if no errors, but the sync and async ideas are great cheers.
Is there a way to pass additional params to the remote submit function?
Something like submit('FormName', params)
for those dealing with 5.3.1, I have added two examples of how to do this based on some comments here and in some other threads. See the code here: https://github.com/psimoneau22/redux-form-submit-from-parent.
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Most helpful comment
I haven't thought through this deeply so there are probably good reasons not to do this, but I would prefer to see something like this:
The primary point being that I wouldn't need to deal with accessing the particular "wrapped" component.