react-hook-form / resolvers

📋 Validation resolvers: Yup, Zod, Superstruct, Joi, Vest, Class Validator, io-ts, Nope, computed-types, typanion, Ajv, TypeBox, ArkType, Valibot, effect-ts and VineJS
https://react-hook-form.com/
MIT License
1.71k stars 155 forks source link

AJV Resolver - When ajv schema contains `default` for certain properties, `getValues()` returns the form data with properties overwritten #647

Open javier-brenes-zen opened 9 months ago

javier-brenes-zen commented 9 months ago

Describe the bug I have an ajv schema that contains default definitions for some properties. Then when calling useForm I pass values with populated data that I retrieved from DB, I can see the data being rendered in UI. When I call getValues function to get the form data without touching any of the inputs, the returned data by getValues no longer contains the initial info provided via values but instead those properties that had a default attribute in the ajv schema are overwritten.

To Reproduce Steps to reproduce the behavior:

  1. Define an ajv schema like this:
    const ajvSchema = {
    type: 'object',
    properties: {
    user: {
      type: 'object',
      properties: {
        name: {
          type: 'string',
          default: 'Camilo',
        },
        lastName: {
          type: 'string',
          default: 'A random lastName',
        },
        email: {
          type: 'string',
          default: 'this@not.com',
        },
      },
    },
    },
    required: ['user'],
    };
  2. When calling useForm on your component make sure you add values:
    const {
    control,
    getValues,
    trigger,
    formState: { errors, isValid },
    } = useForm({
    values: { user: { name: 'Javier', lastName: 'Brenes', email: 'email@fromdb.com' } },
    shouldUnregister: true,
    resolver: ajvResolver(ajvSchema, {
      useDefaults: true,
      removeAdditional: true,
    }),
    });
  3. Render your inputs using Controller
    <div style={{ marginBottom: '10px' }}>
        <label>First Name: </label>
        <Controller
          control={control}
          name="user.name"
          render={({ field }) => (
            <input onChange={field.onChange} value={field.value} />
          )}
        />
      </div>
      <div style={{ marginBottom: '10px' }}>
        <label>Last Name: </label>
        <Controller
          control={control}
          name="user.lastName"
          render={({ field }) => (
            <input
              onChange={handleOnChange(field.onChange)}
              value={field.value}
            />
          )}
        />
      </div>
      <div style={{ marginBottom: '10px' }}>
        <label>email: </label>
        <Controller
          control={control}
          name="user.email"
          render={({ field }) => (
            <input
              onChange={handleOnChange(field.onChange)}
              value={field.value}
            />
          )}
        />
      </div>
  4. Call getValues() without modifying any of the inputs, you will get lastName and email with their default values from the ajv schema, this is wrong because those properties contain info that was passed to the values property in UseForm.

This is what I am getting:

{ "user": { "name": "Javier", "lastName": "A random lastName", "email": "this@not.com" } }

This is what I want to get since I didn't touch any input, and values where set up.

{ user: { name: 'Javier', lastName: 'Brenes', email: 'email@fromdb.com' } },

Codesandbox link (Required) https://stackblitz.com/edit/stackblitz-starters-purvrb?file=src%2FApp.js

Expected behavior getValues should return the set up data via values if none of the inputs were touched. default values in ajv schema should only be used when the property is not part of the form data already.

Screenshots If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

Additional context Add any other context about the problem here.