react-fluent-form icon indicating copy to clipboard operation
react-fluent-form copied to clipboard

Add option to validate a field when another field is changed

Open aranoe opened this issue 5 years ago • 2 comments

Problem Statement

Sometimes it is required to immediately validate a field if the value of another field has been changed. E.g. having two date fields, where one must be before/after the other, it is desired to validate one date based on the others current value.

Prefered API

Option 1

Validate a field, if the value of a specific other field changed:

createForm()({
  fromDate: field.date().validateOnOtherFieldChange("toDate"),
  toDate: field.date().validateOnOtherFieldChange("fromDate")
})

In this case it could also be desried to target multiple other fields. One way is to chain the validation triggers, the other one is to pass an array instead of a single value:

createForm()({
  // chain
  fromDate: field.date().validateOnOtherFieldChange("toDate")
                        .validateOnOtherFieldChange("anotherDate"),
  // pass array
  toDate: field.date().validateOnOtherFieldsChange(["fromDate", "anotherDate"]),
  anotherDate: field.date();
})

Option 2

Validate a field, if any value in the form changed:

createForm()({
  fromDate: field.date().validateOnAnyFieldChange(),
  toDate: field.date().validateOnAnyFieldChange()
})

It might even make sense to implement both Options.

aranoe avatar Mar 25 '20 12:03 aranoe

Option 2 should be a sperate ticket.

For Option 1 it might be better to move this feature from field level configuration to form level configuration:

  • field level configuration should not be dependent on other fields
  • this could also cause more complexity in the future (code and api wise)

Adapted approach for form level configuration

createForm()({
  fromDate: field.date(),
  toDate: field.date(),
  // ...
}).withValidationTriggers({
  fromDate: "toDate",
  toDate: ["firstField", "secondField"]
});

But this doesn't look intuitive enough and on top of that it is not really fluent. It might be better to use a more generic approach, where triggers can be anything:

config.withTriggers({
  fromDate: triggers()
    .validationOnChangeFor("toDate")
    .resetForReturnedFields(value => (value.getUTCFullYear() > 2010? "toDate" : undefined)),
});

(readout as: "fromDate triggers validation on change for toDate" or:

config.withTriggers({
  toDate: triggers([
    onChange().validationFor("fromDate"),
    onBlur().resettingOfReturnedFields(value => (value.getUTCFullYear() > 2010? "anyField" : undefined))
  ])
});

ysfaran avatar Mar 27 '20 16:03 ysfaran

useFluentForm now returns validateField and validateAllFields, so this behaviour can be implemented by hand:

const { values, touched, validateField } = useFluentForm(config);

useEffect(() => {
  if(touched.toDate) {
    validateField("toDate");
  }
},[values.fromDate])

But I'll keep the ticket open for now, since it might be worth implementing triggers directly in react-fluen-form, because the solution above might not be straighforward. Also it could get quite complicated for the users to implement if the form is really big and has a lot of inter-field-dependencies.

ysfaran avatar Mar 31 '20 14:03 ysfaran