iway1 / react-ts-form

https://react-ts-form.com
MIT License
2.01k stars 33 forks source link

Unable to pass options to select field when inside of a complex field type such as an address. #96

Closed roborobs1023 closed 1 year ago

roborobs1023 commented 1 year ago

I have an address field setup as a complex field. Within that field I have two select fields. 1 for the state/region and the other for the country code.

The issue I'm having is I cannot figure out how to pass options down to these fields. Not sure how to get the code below to appear right. md is not behaving with me today. Any idea how to pass the options down to each select field within the address schema?

this is my form.tsx

` const mapping = [ [z.string(), TextInput], [z.boolean(), Checkbox], [z.number(), NumberInput], [PasswordSchema, PasswordField] as const, [PasswordWConfirmSchema, PasswordWConfirmInput] as const, [AddressSchema, AddressInput] as const, [SelectSchema, SelectField] ] as const;

  const MyForm = createTsForm(mapping);

  const SignUpSchema = z.object({
      firstName: z.string().describe("First Name"),
      lastName: z.string().describe("Last Name"),
      email: z.string().email("Enter a real email please.").describe("Email"), // renders TextField
      password: PasswordWConfirmSchema,
      address: AddressSchema,
  })
  export function Form() {
      function onSubmit(data: z.infer<typeof SignUpSchema>) {
          // gets typesafe data when form is submitted
          alert(JSON.stringify(data));
      }

      return (
          <MyForm
              schema={SignUpSchema}
              onSubmit={onSubmit}
              renderAfter={() => <button type="submit">Submit</button>}
              props={{
                  address: {

                  }
              }}
          />
      );
  }

`

My AddressInput.tsx

` const AddressInput = () => { const { field: { value, onChange }, error, } = useTsController<z.infer>(); const line1 = value?.line1; const line2 = value?.line2; const locale = value?.locale; const region = value?.region; const postalCode = value?.postalCode; const countryCode = value?.countryCode; return (

{error?.line1 &&
{error.line1.errorMessage}
} {error?.line2 &&
{error.line2.errorMessage}
}
{error?.locale &&
{error.locale.errorMessage}
}
                  <div style={{ maxWidth: "70%" }}>
                      <label
                          style={{
                              fontSize: 16,
                              display: "flex",
                              gap: ".5em",
                              marginBottom: ".5rem",
                              justifyContent: "flex-end",
                          }}
                      >
                          Zip Code
                          <input
                              style={{ padding: "0.25rem", maxWidth: "50%", }}
                              type="text"
                              value={postalCode}
                              onChange={(e) => onChange({ ...value, postalCode: e.target.value })}
                          />
                      </label>
                      {error?.postalCode && <div style={{ color: "red" }}>{error.postalCode.errorMessage}</div>}
                  </div>
              </div>

          </div>
      )
  }

  export default AddressInput

  const zipcodeRegex = RegExp('^\d{ 5} -\d{ 4} |\d{ 5} | [A - Z]\d[A - Z]\d[A - Z]\d$')
  export const AddressSchema = createUniqueFieldSchema(z.object({
      line1: z.string().describe("Street Address"),
      line2: z.string().optional(),
      locale: z.string().describe("City"),
      region: SelectSchema.describe("State"),
      postalCode: z.string().regex(zipcodeRegex, "Please Enter a valid Zip Code.").describe("Zip Code"),
      countryCode: SelectSchema.describe("Country Code"),
  }), "address")

Select function SelectField({ options }: { options: string[] }) { const { field, error } = useTsController(); const label = useDescription(); return ( <> <label style={{ fontSize: 16, display: "flex", gap: ".5rem", marginBottom: ".5rem", justifyContent: "flex-end", }}

{label.label}

            <select
                value={field.value ? field.value : "none"}
                onChange={(e) => {
                    field.onChange(e.target.value);
                }}
            >
                {!field.value && <option value="none">Please select...</option>}
                {options.map((e) => (
                    <option key={e} value={e}>
                        {e}
                    </option>
                ))}
            </select>
        </label>
        <span>{error?.errorMessage && error.errorMessage}</span>
    </>
);

}

export default SelectField

export const SelectSchema = createUniqueFieldSchema(z.string(), "DropdownSelect")`

roborobs1023 commented 1 year ago

I figured out a way around this by just creating props for the address function and passing them to each select manually created within the AddressInput Field. but would think there would be a way to allow use of the SelectField Component.

iway1 commented 1 year ago

I think creating a prop for the complex input type is a good solution if it's rendering child SelectField components