Jub10
Jub10

Reputation: 313

react-hook-form Controller component does not acknowledge react-native-dropdown-picker input as filled

apologies as I'm still fairly new to React Native. I encountered this issue upon replacing some poorly styled dropdown picker with a 3rd party library (react-native-dropdown-picker). I was able to create a pretty workable solution, but the form uses react-hook-forms for submission and validation purposes. It's currently indicating that my searchable dropdown components are still empty, even when they are clearly displaying values

export const ControlledSearchableInput = (
  props: ControlledSearchableInputProps
) => {
  return (
    <Controller
      control={props.control}
      name={props.name}
      defaultValue={props.defaultValue}
      render={({ onChange, value }) => (
        <SearchableInput
          onChange={onChange}
          value={value ?? value.name}
          dataType={props.dataType}
          hideLabel={props.accountType ?? false}
          accountType={props.accountType ?? false}
          placeholder={props.placeholder ?? ""}
          error={props.error}
        />
      )}
    />
  );
};
export function SearchableInput<T>({
  onChange,
  value,
  dataType,
  error,
  label,
  hideLabel,
  groupPosition,
  placeholder,
  disabled = false,
  accountType,
}: SearchableInputProps<T>) {
  const [open, setOpen] = useState(false);
  const [val, setVal] = useState<string>(value);
  const [loading, setLoading] = useState(false);

  const getDataAsync = async (search: string) => {
    if (search) {
      setLoading(true);
      switch (dataType) {
        case "country":
          return (await mobileApiManager.Countries.getCountries({ search }))
            .results;
        case "state":
          return (
            (await mobileApiManager.States.getStates({ search })).results ?? []
          );
      }
    } else {
      setLoading(false);
      return [];
    }
  };

  const currentList = useAsync<SearchableInputType[]>((searchText) =>
    getDataAsync(searchText)
  );

  const listItems = currentList.value
    ? currentList.value.map((item) => {
        return { label: item.name, value: item.id };
      })
    : [];

  const [items, setItems] = useState(listItems);

  useEffect(() => {
    setItems(listItems);
    if (listItems.length >= 0) {
      setLoading(false);
    }
  }, [currentList.value]);

  return (
    <View style={{ marginBottom: error ? 16 : 8 }}>
      <DropDownPicker
        open={open}
        value={val}
        loading={loading}
        items={items ?? []}
        setOpen={setOpen}
        setValue={setVal}
        setItems={setItems}
        searchable
        disabled={disabled}
        placeholder={placeholder ?? ""}
        searchPlaceholder="Search..."
        labelProps={{ numberOfLines: 1 }}
        onChangeSearchText={currentList.execute}
        listMode="MODAL"
        onChangeValue={onChange}
      />
      {!!error && <ErrorMessage text={error} />}
    </View>
  );
}

export default function EditAddresses(props: EditAddressesProps) {
  const { fields, append, remove } = useFieldArray({
    control: props.control,
    name: "addresses",
    keyName: "customIDAddr",
  });

  return (
    <View>
      <ProfileRowView marginBottom={`${scale(5)}`} marginTop={`${scale(25)}`}>
        <NameText margin={"0"}>{getLocalString(Strings.address)}</NameText>
        <AddButtonWithLabel
          onPress={() => {
            append(defaultAddress);
          }}
        />
      </ProfileRowView>
      {fields.map((item: any, index: number) => (
        <View
          key={`${item.id}${item.uuid}`}
          style={{ marginBottom: scale(13) }}
        >

         //...Other components
        
          <ControlledSearchableInput
            accountType
            placeholder={getLocalString(Strings.state)}
            control={props.control}
            name={`addresses[${index}].state`}
            dataType={"state"}
            // stateId={`addresses[${index}].stateId`}
            defaultValue={item.state ?? ""}
            error={props.errors?.addresses?.[index]?.state?.message}
          />
          //...Other components
        
          <ControlledSearchableInput
            control={props.control}
            name={`addresses[${index}].country`}
            placeholder={"Country"}
            dataType={"country"}
            // countryId={`addresses[${index}].countryId`}
            accountType
            defaultValue={item.country ?? ""}
            error={props.errors?.addresses?.[index]?.country?.message}
          />
         
        </View>
      ))}
    </View>
  );
}

Address form

Any help would be greatly appreciated

Upvotes: 1

Views: 1270

Answers (1)

Vyrotek
Vyrotek

Reputation: 5439

I was able to get this working with the Controller with this configuration.

...
<Controller
  ...
  render={({ field }) => (
    <DropDownPicker
       value={field.value}
       setValue={(callback: any) => field.onChange(callback())}
       items={items}
...

Upvotes: 5

Related Questions