2

I have N redux-forms on the page and each form has its own submit handler with validation rules.

When user clicks to the Submit button, which is outside of all forms (using Remote Submit), I trigger submit for each of the forms and want to understand where and how I can catch the event that every form has been submitted successfully. In case all forms are valid - I need to redirect user to another page.

Could you please give any advice how this can be achieved?

borN_free
  • 846
  • 7
  • 18

2 Answers2

1

On solution:

  • Have variables submittedForms = 0 and allFormsSubmitted = false in your initial store state;
  • On each form submission, send an action that increases submittedForms by 1, and sets allFormsSubmitted = true only if state.submittedForms === N. Possibly also reset the counter then.
  • Have another component listen to changes of allFormsSubmitted.

Another is, on each form submission, to read directly the state generated by redux-forms from the store for a flag such as submitted=true that is likely there for each form you defined. If all have the flag set, trigger an action that makes allFormsSubmitted = true. That way, you don't have to manage the number of forms N (susceptible to change).

Edit: Example of custom reducer that listens to redux-forms actions:

let N = 7;
let defaultState = {
    allFormsSubmitted: false,
    submittedForms: {},
}    

let customReducer = (state = defaultState, action) => {
  switch (action.type) {

    case "SUBMIT_SUCCEDED":   // the same as the redux-forms action type - just a string
      state.submittedForms[action.formName] = true;
      if (Object.keys(submittedForms).length === N) {
        state.allFormsSubmitted = true;
      }
      return {...state};

    case "SUBMIT_FAILED":
      state.submittedForms[action.formName] = false;
      state.allFormsSubmitted = false;
      return {...state};

  ...  
  }
}
JulienD
  • 6,170
  • 8
  • 44
  • 72
  • used the second solution (a little bit modified): I pass `submitted` flag for each form in Container through `connect` like `xFromSuccessfullySubmitted: hasSubmitSucceeded(CLIENT_INFORMATION_FORM)(state), ...` and then, in `componentWillReceiveProps()` check `if (nextProps.xFromSuccessfullySubmitted && nextProps.yFromSuccessfullySubmitted && ...) { dispatch allFormsSuccessfullySubmitted() }` Works well but still not convinced if this is a best solution – borN_free Oct 19 '17 at 12:47
  • It is a bad idea to dispatch an action in `componentWillReceiveProps`, you risk an infinite loop when all are submitted. Sending actions after you have already reduced is an anti-pattern, too. It must all be reduced at once. Note that you can have several reducers listening to the same action. – JulienD Oct 19 '17 at 12:51
  • got it. But then I don't understand where should I check that all forms are submitted, in what action? redux-form dispatches `SUBMIT_SUCCEDED` after form submit, so I can't determine if all forms are succeded during submission. Just to doucle confirm: I submit all forms at the same time, and then redux-form dispatches its own actions (which can be `SUBMIT_SUCCEDED` or `SUBMIT_FAILED` – borN_free Oct 19 '17 at 12:59
  • I added an example of how you can listen to redux-forms actions to react at reduction time. I assume that the actions carry some identifier `formName` of the form. – JulienD Oct 19 '17 at 13:20
  • Thank you, but it does not answer the question where should I dispatch `redirect` action? With such reducer we know that `allFormsSubmitted === true` in the state, but this is a reducer where we can't dispatch any actions. That's why I thought it should be dispatched in `componentWillRecieveProps` – borN_free Oct 19 '17 at 14:43
  • Actually with this "remote submit" you completely determine the content of the `submit` function, so you are completely in control of the promise inside it. You can just trigger the redirect when the promise is fulfilled, like in the example in https://redux-form.com/7.0.4/examples/remotesubmit/ that throws SubmissionErrors or alerts when there is a success. Replace the alert with the redirect. – JulienD Oct 19 '17 at 16:45
  • I can't use promis from submit handler because I have many of them (N forms), but only of `submitAllForms` action: `function submitAllForms(dispatch) { dispatch(submit(CLIENT_INFORMATION_FORM)); dispatch(submit(CONTRACT_DETAILS_FORM)); }` So, there is no one general Promise for all forms – borN_free Oct 26 '17 at 15:09
  • There is one onSubmit-promise for each form and in each of them you can check if all the forms were submitted as discussed before. – JulienD Oct 26 '17 at 15:11
  • Default `onSubmit` implementation gets only `values`, `dispatch` and `props` parameters. There is no `getState()` function, it means it's impossible to get the actual state at the moment when current onSubmit passes validation. Should I somehow inject `getState` function to `onSubmit`? – borN_free Oct 26 '17 at 15:55
1

where and how I can catch the event that every form has been submitted successfully and I need to redirect user to another page.

As you are submitting all the forms at the same time , i encountered the same problem , thats how i managed to resolve this issue:

Callback function passed to action creator (createPost)

    onSubmit(values){
        this.props.createPost(values, () => {
            this.props.history.push('/');
        });

It will not redirect the user unless posts(forms) are successfully posted to the backend api or database , in this case user will be programmatically redirected to the ('/') index.html , You can pass any Route to this.props.history.push(' ') as long as that <Route /> exists in <BrowserRouter> ('react-router-dom') the main (index.js) file

Inside action creator , i used axios to make a post request to backend API and once its successfully posted .then() i passed a callback function to redirect the user

    import axios from 'axios';
    export const CREATE_POST = 'create_post';
    const ROOT_URL = 'http://xyz.app.com/api';
    const API_KEY = '?key=xxxxx';

    export function createPost(values, callback) {
        const request = axios.post(`${ROOT_URL}/posts${API_KEY}`, values)
            .then(() => callback());
        return {
            type: CREATE_POST,
            payload: request
        };
    }

You can read more about programmatically navigation Here

Aaqib
  • 7,595
  • 3
  • 17
  • 25
  • I agree. Indeed it looks like the remote submit of redux-forms actually gives you complete control of the outcome, like in this example for submission validation: https://redux-form.com/7.0.4/examples/submitvalidation/. – JulienD Oct 19 '17 at 16:40