Hemant Agarwal
Hemant Agarwal

Reputation: 15

Set default value in Autocomplete field of Material-UI

I'm trying to set a default value to autocomplete, the value of which is getting fetched from the URL in useEffect hook, but I'm unable to do so.

I'm fetching some data from a URL and then setting it to selectedMode & the variable selectedMode is used in setting default value in autocomplete field, but if I'm setting some default value in the selected mode - it is getting set as default value in autocomplete field, but even after getting updated the value is not changing.

I think that its because the autocomplete field is getting loaded before receiving data from the URL.

const [update, setUpdate] = useState([])
const [selectedMode, setSelectedMode] = useState([{ name: '' }])
const mode = [
    { name: 'Air' },
    { name: 'Train' },
    { name: 'Surface' }
]
useEffect(() => {
    axios
        .get(`http://127.0.0.1:8000/bill/${id}`)
        .then(response => {
            const data = response.data
            setUpdate(data)
            setSelectedMode([{ name: data.mode }])
        })
}, [])

return (
        <>
            <Autocomplete
                defaultValue={selectedMode.name ? selectedMode : null}
                options={mode}
                getOptionLabel={option => option.name}
                getOptionSelected={(option, value) => option.name === value.name}
                onChange={(e, value) => setUpdate({
                    ...update,
                    mode: value ? value.name : ''
                })}
                renderInput={params =>
                    <TextField
                        {...params}
                        required
                        label="Mode"
                        variant="outlined"
                    />}
            />
        <>
      )

The alternate way i tried is instead of setting defaultValue, I'm using - value={selectedMode} - and on onChange event I'm updating the value stored in selectedMode. But this also didn't give me desired output.

Below is the code :-

const [update, setUpdate] = useState([])
const [selectedMode, setSelectedMode] = useState([{ name: '' }])
const mode = [
    { name: 'Air' },
    { name: 'Train' },
    { name: 'Surface' }
]
useEffect(() => {
    axios
        .get(`http://127.0.0.1:8000/bill/${id}`)
        .then(response => {
            const data = response.data
            setUpdate(data)
            setSelectedMode([{ name: data.mode }])
        })
}, [])

return (
        <>
            <Autocomplete
                value={selectedMode.name}
                options={mode}
                getOptionLabel={option => option.name}
                getOptionSelected={(option, value) => option.name === value.name}
                onChange={(e, value) => setSelectedMode([{
                    ...selectedMode,
                    name: value ? value.name : ''
                }])}
                renderInput={params =>
                    <TextField
                        {...params}
                        required
                        label="Mode"
                        variant="outlined"
                    />}
            />
        <>
      )

Warning I'm getting while no option is selected :- screenshot of the warning -- warning

warning --

react_devtools_backend.js:6 Material-UI: The value provided to Autocomplete is invalid.
None of the options match with `{"name":""}`.
You can use the `getOptionSelected` prop to customize the equality test. 
    at Autocomplete (http://localhost:3000/static/js/0.chunk.js:41722:35)
    at WithStyles (http://localhost:3000/static/js/0.chunk.js:47043:31)
    at DetailData (http://localhost:3000/static/js/main.chunk.js:1311:86)
    at Route (http://localhost:3000/static/js/0.chunk.js:90811:29)
    at Switch (http://localhost:3000/static/js/0.chunk.js:91013:29)
    at App (http://localhost:3000/static/js/main.chunk.js:207:75)
    at Router (http://localhost:3000/static/js/0.chunk.js:90448:30)
    at BrowserRouter (http://localhost:3000/static/js/0.chunk.js:90082:35)

Upvotes: 1

Views: 6205

Answers (2)

Mordechai
Mordechai

Reputation: 16184

Your second solution should work, but here are a few changes you should make:

Since you can only select on at a time there's no reason to wrap the mode in an array, in fact your code will fail, since array doesn't have a name property.

The value should be one item of the options array, pass the actual object, not just the name property. You shouldn't use a dummy object for no selection, use null instead.

Your code should look like this:

const [update, setUpdate] = useState([])
const [selectedMode, setSelectedMode] = useState(null)
const mode = [
    { name: 'Air' },
    { name: 'Train' },
    { name: 'Surface' }
]
useEffect(() => {
    axios
        .get(`http://127.0.0.1:8000/bill/${id}`)
        .then(response => {
            const data = response.data
            setUpdate(data)
            setSelectedMode({ name: data.mode })
        })
}, [])

return (
        <>
            <Autocomplete
                value={selectedMode}
                options={mode}
                getOptionLabel={option => option.name}
                getOptionSelected={(option, value) => option.name === value.name}
                onChange={(e, value) => setSelectedMode({
                    name: value ? value.name : ''
                })}
                renderInput={params =>
                    <TextField
                        {...params}
                        required
                        label="Mode"
                        variant="outlined"
                    />}
            />
        <>
      )

Upvotes: 2

Jono Calvo
Jono Calvo

Reputation: 56

this just an idea, try to set a loading variable, then in the useEffect set it to false. Use this variable in a if to render your Autocomplete when loading is false.

const [update, setUpdate] = useState([])
const [selectedMode, setSelectedMode] = useState([{ name: '' }])
const [loading, setLoading] = useState(true)
const mode = [
{ name: 'Air' },
{ name: 'Train' },
{ name: 'Surface' }
]
useEffect(() => {
axios
    .get(`http://127.0.0.1:8000/bill/${id}`)
    .then(response => {
        const data = response.data
        setUpdate(data)
        setSelectedMode([{ name: data.mode }])
        setLoading(false)
    })
}, [])

I believe that when you are in the useEffect and set a value the return won't load it as you want it. Let me know if that works.

Upvotes: 0

Related Questions