sadasdadssad
sadasdadssad

Reputation: 105

How return id in autocomplete instead of .country's name?

I use Autocomplete from @Mui. I made this component

const Profile = () => {
  const {
    register,
    handleSubmit,

    setValue,
    formState: { errors },
  } = useForm({});

  const [countries, setCountries] = useState([]);

  const submit = async (value) => {
    console.log(value);
    console.log(value.countries);
  };

  useEffect(() => {
    axios.get("get-countries").then((data) => {
      setCountries(data.data);
    });
  }, []);

  return (
    <>
      <form method="post" onSubmit={handleSubmit(submit)}>
        {categories.countries && (
          <Autocomplete
            id="country-select-demo"
            options={categories.countries}
            autoHighlight
            getOptionLabel={(option) => option.country}
            renderOption={(props, option) => (
              <Box
                component="li"
                sx={{ "& > img": { mr: 2, flexShrink: 0 } }}
                {...props}
              >
                <img
                  loading="lazy"
                  width="20"
                  src={`https://flagcdn.com/w20/${option.symbol.toLowerCase()}.png`}
                  srcSet={`https://flagcdn.com/w40/${option.symbol.toLowerCase()}.png 2x`}
                  alt=""
                />
                {option.country}
              </Box>
            )}
            renderInput={(params) => (
              <TextField
                {...params}
                label="Country"
                inputProps={{
                  ...params.inputProps,
                  autoComplete: "country",
                }}
                {...register("country", {
                  required: true,
                })}
              />
            )}
            onChange={(e, value) => setValue("country", value?.id)}
          />
        )}

        <Button variant="contained" type="submit" sx={{ marginTop: 3 }}>
          Submit
        </Button>
      </form>
    </>
  );
};

Problem is that I need to return after submit in console.log id of country but it return country. Backend return json which looks like this: {"id":1,"country":"United Kingdom","symbol":"uk"}. You can see that I tryed using onChange in order to change defaul value but it doesn't work. I can use hook useState but I use react-hooks-form są it doesn't matter. I need to use register and return id from Autoselect. How can I return id instead of country?

@Edit

I may not have explained everything thoroughly. I have a problem with the Autocomplete component. With normal select, I can add a custom value to each option, such as.

<select>
   <option value="1">United Kingdom</option> 
</select>

But I don't know is to do similarly in the case of this component

Upvotes: 3

Views: 340

Answers (1)

kofeigen
kofeigen

Reputation: 1635

This link displays a diff showing the only changes needed to get the code working. With these changes in place, the console.log output displays an object with the id property. The complete, updated version of the function is copied below.

A live demo (without the country flags) is available.

The problem was more related to react-hook-form than to MUI Autocomplete.

MUI Autocomplete getOptionLabel property

The MUI docs say this about getOptionLabel:

Used to determine the string value for a given option. It's used to fill the input (and the list box options if renderOption is not provided).

The return values from getOptionLabel (a callback function) populate the value property of the native HTML <input> element. When a form is submitted react-hook-form reads data from the value property of the form's fields. In the code, getOptionLabel returns the country name, this is what is read (and returned upon form submission) by react-hook-form. This is the default behaviour when form fields are registered using the react-hook-form register function.

The important change needed to the code is to avoid registering the element with react-hook-form. This allows us to avoid default behavior. Since, id is desired, not the country name, we need to use the react-hook-form setValue function to switch from using the default <input> value property to id.

The react-hook-form docs say:

It's recommended to register the input's name before invoking setValue.

However:

you can setValue to a unregistered input.

Updated code

const Profile = () => {
  const {
    register,
    handleSubmit,

    setValue,
    formState: { errors },
  } = useForm({});

  const [countries, setCountries] = useState([]);

  const submit = async (value) => {
    console.log(value);
    console.log(value.countries);
  };

  useEffect(() => {
    axios.get("get-countries").then((data) => {
      setCountries(data.data);
    });
  }, []);

  return (
    <>
      <form method="post" onSubmit={handleSubmit(submit)}>
        {countries && (
          <Autocomplete
            id="country-select-demo"
            options={countries}
            autoHighlight
            getOptionLabel={(option) => option.country}
            renderOption={(props, option) => (
              <Box
                component="li"
                sx={{ "& > img": { mr: 2, flexShrink: 0 } }}
                {...props}
              >
                <img
                  loading="lazy"
                  width="20"
                  src={`https://flagcdn.com/w20/${option.symbol.toLowerCase()}.png`}
                  srcSet={`https://flagcdn.com/w40/${option.symbol.toLowerCase()}.png 2x`}
                  alt=""
                />
                {option.country}
              </Box>
            )}
            renderInput={(params) => (
              <TextField
                {...params}
                label="Country"
                inputProps={{
                  ...params.inputProps,
                  autoComplete: "country",
                }}
              />
            )}
            onChange={(e, value) => setValue("id", value?.id)}
          />
        )}

        <Button variant="contained" type="submit" sx={{ marginTop: 3 }}>
          Submit
        </Button>
      </form>
    </>
  );
};

Upvotes: 0

Related Questions