score:16

Accepted answer

Library author here. I'm always fascinated by new ways people can invalidate my assumptions. I mean that in a sincerely positive way, as it results in learning.

🏁 Final Form makes the assumption that your validation functions are "pure" or "idempotent", i.e. will always return the same result when given the same values. This is why it doesn't run the synchronous validation again (just to double check) before allowing the submission: because it's already stored the results of the last time it ran it. By using an outside timer, you've invalidated that assumption.

If you have a better/simpler/"more official" solution, I'd still love to see it!

No need for mutators or decorators for this problem.

The more official way to do this would be to run the check (you could even reuse this.validate) in onSubmit. The only tricky part is that the error will come back as meta.submitError, so you need to check for both when displaying your error. Like so:

Edit Force revalidation on submit (React Final Form)

score:1

Since you want to enforce re-validation OR stop submission of form based on the interval, why not use disabled on submit button?

// interval less than 900 = 15 minutes
<button type="submit" disabled={this.state.interval>=900}>
    Submit
</button>

I have also read docs of react-final-form but I thinks it's more easy unless you have a specific case to address using meta.

score:1

Got another use case where manual triggering validation is needed: In this case we got an student form, in case we got a new student, a field called temporary password must be fullfilled, if not that field is not mandatory, to keep it simple we update the validation schema on the fly (we had a similar case with a validation that needs to be included whenever some fetch operation was completed).

We applied @uche-ozoemena and it worked fine, but @erik-r is this solution considered a hack or is something that we can use as an approved workaround in scenarios where we need to manually trigger validations?

We got something like (using fonk-final-form):

  React.useEffect(() => {
    if (isUserCreation) {
      const newDataFormvalidationSchema = {
        ...dataFormvalidationSchema,
        field: {
          ...dataFormvalidationSchema.field,
          temporaryInitialPassword: [
            ...dataFormvalidationSchema.field.temporaryInitialPassword,
            Validators.required,
          ],
        },
      };

      dataFormValidation.updateValidationSchema(newDataFormvalidationSchema);
    }
  }, [isUserCreation]);

  return (
    <Form
      initialValues={initialData}
      mutators={{ mutateValue: mutateValue }}
      onSubmit={values => {
        save(values);
      }}
      validate={dataFormValidation.validateForm}

score:2

You're already putting a function inside onSubmit, why not just add the functionality you want to it? event.preventDefault() and then work with your validate function, it' s a part of the component and accessible to you.

handleOnSubmit(e){
  let value = document.querySelector("input").value 
  if (!!this.validate(value)){
    e.preventDefault();
    alert("Prevented submit event")
  } else{
    alert("Form submitted")
  }
}

now just use this function in the form onSubmit prop(I put in bot since i wasn't sure about the component structure):

<Form onSubmit={this.handleOnSubmit}>...</Form>
<form onSubmit={this.handleOnSubmit}>

And remove the submitListener decorator from the Form component:

decortaor={submitListener}

Now it will check the validation before submitting and prevent it if not validated.

score:2

So I have found a way to do this! 🎉 I use a mutator and use it's changeValue function to 'change' the value of the relevant field (I supply the same value). This in turn notifies all relevant parties of the change to the form's state, and a validation is triggered. The key is to call the mutator inside the submit handler, which therefore ensures that the validation is performed when the form is submitted. Have a look at this new Sandbox.

The relevant bits are as follows:

// this is a stateful component
...
...
  mutateValue([name], state, { changeValue }) {
    // change the value to the same value, thus
    // triggering a revalidation of the same value
    changeValue(state, name, value => value);
  }

  handleSubmit(values) {
    alert("submitted");
  }

  render() {
    return (
  ...
  ...
        <Form
          onSubmit={this.handleSubmit}
          mutators={{ mutateValue: this.mutateValue }}
          render={({
            handleSubmit,
            form: {
              mutators: { mutateValue }
            }
          }) => {
            const mutateBeforeSubmit = values => {
              // supply the name of the relevant form field
              mutateValue("revalidate");
              // submit handler gets called if revalidation still passes
              handleSubmit(values);
            };
            return (
              <form onSubmit={mutateBeforeSubmit}>
              ...
              ...
              </form>
            );
          }}
        />
        ...
        ...

And because it's triggering the same validation mechanism, meta gets used accordingly!

If you have a better/simpler/"more official" solution, I'd still love to see it!


Related Query

More Query from same tag