formsy-react icon indicating copy to clipboard operation
formsy-react copied to clipboard

Validation `values` 'undefined' with 'defaultValue' set

Open DamonBlais opened this issue 4 years ago • 3 comments

Hello!

So, I have a lengthy, multi-page form that I've used LocalStorage to save the state therein.

const [state, setState] = useState<AccountSetupForm>({} as AccountSetupForm)

// Load from LocalStorage on Page Load
useEffect(() => {
  const savedState = window.localStorage.getItem(LSKEY_ACCOUNT_SETUP_FORM)
  if (savedState) {
    setState({ ...state, ...JSON.parse(savedState) })
  }
}, [])

However, when I restore the state to the form (which updates its values), the validation doesn't see this.

The Next/Submit button in the form is disabled on load, even if all fields were populated on load.

const [disabled, setDisabled] = useState<boolean>(false)
return (
  <Form
    onValid={() => setDisabled(false)}
    onInvalid={() => setDisabled(true)}
  >
    {/* ... */}
  </Form>
)

Then, upon editing any field, only that field is defined in the validation, all else are undefined.

addValidationRule('isPhone', (values: Values, value?: string): boolean => {
  console.log(values) // only the field I edited is defined, everything else is `undefined`
  setState(values) // is there a better way to access the form state than inside a validator?

  if (value) {
    const code = values['phone-country-code']
    if (code) { // <-- `code` is `undefined` even though its field has a `defaultValue`
      return validator.isMobilePhone(
        `${code.slice(0, code.indexOf(':'))}${value}`,
        'en-US',
        {
          strictMode: true,
        }
      )
    }
  }

  return false
})

How do I tell the validation to grab the values of all the fields after I've loaded them?


Example Form Input (for completeness of reproducability sake):

<Form.Input
  autoComplete="email"
  defaultValue={state.Email}
  label="Email Address"
  name="email"
  type="email"
  
  {/* Had to wrap this because idk how to access values except in a validator */}
  validations="isEmailWrapped"

  validationErrors={{
    isEmail: 'Doesn\'t look like a valid email address...',
  }}
  errorLabel={errorLabel}
/>

DamonBlais avatar Jun 26 '21 23:06 DamonBlais

If the user triggers an edit (deletes and re-types a character) in every field, then the form realizes all the inputs have values, and re-enables the Next/Submit button as expected. formsy-react is working EXCEPT for it ignoring defaultValue for initial state as mentioned above.

The input fields render with the default values, it's only the validation that is oblivious to them. to clarify.

DamonBlais avatar Jun 26 '21 23:06 DamonBlais

Related to but not fixed by the steps in: #566

DamonBlais avatar Jun 26 '21 23:06 DamonBlais

It is an issue of async, your form get rendered with undefined values once, then the useEffect kicks in, fills the defaultValue, but nothing update formsy about the change since defaultValue is ment to be used at the first render. You can wait till the localStorage is loaded and re-render again. There are 2 ways that come to mind:

  1. Show loading instead of the form.
  2. Use key on the form that will be related to the async operation.
const MyForm = () => {
  const [state, setState] = useState<AccountSetupForm>({} as AccountSetupForm);
  const [isLoaded, setLoaded] = useState(false);

  // Load from LocalStorage on Page Load
  useEffect(() => {
    const savedState = window.localStorage.getItem(LSKEY_ACCOUNT_SETUP_FORM)
    if (savedState) {
      setState({ ...state, ...JSON.parse(savedState) })
      setLoaded(true);
    }
  }, []);

  return <Form
    onValid={() => setDisabled(false)}
    onInvalid={() => setDisabled(true)}
    key={`form-${isLoaded}`} // <---
  >
    <Form.Input
    autoComplete="email"
    defaultValue={state.Email}
    label="Email Address"
    name="email"
    type="email"
    validations="isEmailWrapped"
    validationErrors={{
      isEmail: 'Doesn\'t look like a valid email address...',
    }}
    errorLabel={errorLabel}
   />
</Form>
}

felixmosh avatar Jul 24 '22 21:07 felixmosh

@DamonBlais can we close this issue?

felixmosh avatar Aug 24 '22 12:08 felixmosh

Sorry, that's a GitHub account I don't use often (generally by mistake.)

I'll try and login to close this.

AlbinoGeek avatar Aug 25 '22 00:08 AlbinoGeek

This can be closed.

Can't find my 2fa for this

On Wed., Aug. 24, 2022, 5:41 p.m. Damon Blais, @.***> wrote:

Sorry, that's a GitHub account I don't use often (generally by mistake.)

I'll try and login to close this.

— Reply to this email directly, view it on GitHub https://github.com/formsy/formsy-react/issues/642#issuecomment-1226639191, or unsubscribe https://github.com/notifications/unsubscribe-auth/AKTKHMIF7CR2KA2HG2E7CQDV226LNANCNFSM47LZESAA . You are receiving this because you were mentioned.Message ID: @.***>

DamonBlais avatar Aug 25 '22 00:08 DamonBlais