Missak Boyajian
Missak Boyajian

Reputation: 2245

React Form Hook with Autocomplete Material UI

I have a countries array which contains id and name. Currently I am using a Material UI Autocomplete element and I have a react hook form. When I submit the form, I want to fetch the country Id. Currently it is posting the country name. Is there a way to post the ids instead of the names without going and fetching the id from the name.

   <Autocomplete
      className="form-item"
      options={countries}
      getOptionLabel={option => option.name}
      renderInput={params => (
        <TextField
          {...params}
          inputRef={register}
          label="Country"
          name="country"
          placeholder="Select a Country"
          InputLabelProps={{
            shrink: true
          }}
          variant="outlined"
        />
      )}
    />

Upvotes: 4

Views: 6201

Answers (3)

DINA TAKLIT
DINA TAKLIT

Reputation: 8428

Here is a simplest way to create it, render your Autocomplete component inside Controller from react hook from, use onChange and value from the render function to control the value

<Controller
control={control}
name="type"
rules={{
  required: 'Veuillez choisir une réponse',
}}
render={({ field: { onChange, value } }) => (
  <Autocomplete
    freeSolo
    options={['field', 'select', 'multiple', 'date']}
    onChange={(event, values) => onChange(values)}
    value={value}
    renderInput={(params) => (
      <TextField
        {...params}
        label="type"
        variant="outlined"
        onChange={onChange}
      />
    )}
  />
)}

Upvotes: 0

gdh
gdh

Reputation: 13702

Use react-hook-form's Controller and put the entire Autocomplete in the as prop. With this, when you submit the form you will get the entire object of the selected option.

Note: In react-hook-form version 6.x, the onChange is removed, the as prop will take a function and you can obtain onChange as param.

Working demo - v6

    <Controller
        as={({ onChange }) => (
          <Autocomplete
            className="form-item"
            options={countries}
            onChange={(_, data) => onChange(data)}
            getOptionLabel={option => option.label}
            renderInput={params => (
              <TextField
                {...params}
                label="Country"
                placeholder="Select a Country"
                InputLabelProps={{
                  shrink: true
                }}
                variant="outlined"
              />
            )}
          />
        )}
        name="country"
        control={control}
        defaultValue={{ label: "The Shawshank Redemption", id: "1994" }}
      />

Note: If you are using v5x then see demo and code snippet below.

Working demo - v5

   <Controller
        as={
          <Autocomplete
            className="form-item"
            options={countries}
            getOptionLabel={option => option.label}
            renderInput={params => (
              <TextField
                {...params}
                label="Country"
                placeholder="Select a Country"
                InputLabelProps={{
                  shrink: true
                }}
                variant="outlined"
              />
            )}
          />
        }
        name="country"
        control={control}
        onChange={([, data]) => data}
        defaultValue={{ label: "The Shawshank Redemption", id: "1994" }}
      />

Edit: based on comment You can use setValue to set default values based on an api.

code snippet:

useEffect(() => {
    setTimeout(() => { // fake api
      setValue(
        "country",
        { label: "hi The Godfather", id: "1972" },
        { shouldDirty: true }
      );
    }, 2000);
  }, []);

Demo v6 above is updated.

Also see official demo of setValue usage here

Upvotes: 3

Chris
Chris

Reputation: 6631

I'm afraid that there is not an 'easy' way to get the ids with the current setup.

However, you can hook into the Autocomplete#onChange event and use the value prop to take over the internal value state of the Autocomplete component. This results in having the value available in your component and use this to your advantage.

In the example below, the id will be available in the form data as country-id.

function CountryAutocomplete() {
  const [value, setValue] = useState(); // `[]` for multiple

  return (
    <React.Fragment>
      <Autocomplete
        className="form-item"
        value={value}
        onChange={(event, value) => setValue(value)}
        options={countries}
        getOptionLabel={option => option.name}
        renderInput={params => (
          <TextField
            {...params}
            inputRef={register}
            label="Country"
            name="country"
            placeholder="Select a Country"
            InputLabelProps={{
              shrink: true
            }}
            variant="outlined"
          />
        )}
      />
      <input value={value?.id} name="country-id" />
    </React.Fragment>
  );
}

Upvotes: -1

Related Questions