How do I get my options to display with Autocomplete (MUI)? - reactjs

I'm trying to help my friend figure out why Autocomplete isn't showing anything.
Below is the code:
var names = [];
const schoolList = async () => ( await axios.get("http://localhost:5000/api/grabUnivNames/")
.then((res) => {
// schoolList = JSON.stringify(res.data.msg)
names = res.data.msg.map(user => user.school_name);;
console.log(names)
// return res.data.msg.map(user => user.school_name);
})
.catch((error) => {
console.log("ERROR");
console.log(error);
})
);
schoolList();
return() with Autocomplete:
<Autocomplete
options={names}
sx={{ width: 300 }}
renderInput={(params) => <TextField {...params} label="School Name" />}
/>
What names contains:
What shows:
I only started learning about Autocomplete today but I think the problem may be in how he is obtaining names or how names is formatted but I am also very unfamiliar with Autocomplete.
How can I get names to display on the dropdown?

first of all i am assuming that your data fetching is done correctly and you use react functional based components.
You will need 2 main requirements to achieve what you want
first of all replace normal variable names with useState hook of
names array and loading boolean, cause normal variables will not have dynamic values over multiple renders
MUI Autocomplete supports async operation , so you will attach the getSchoolList handler to onOpen prop, and loading prop so let the component show progress while loading
const [names,setNames] = React.useState([])
const [loading, setLoading] = React.useState(false)
const getSchoolList = () => {
setLoading(true)
axios.get("http://localhost:5000/api/grabUnivNames/")
.then((res) => {
// schoolList = JSON.stringify(res.data.msg)
const namesArr = res.data.msg.map(user => user.school_name)
setNames(namesArr)
// return res.data.msg.map(user => user.school_name);
})
.catch((error) => {
console.log("ERROR");
console.log(error);
}).finally(() => setLoading(false))
}
<Autocomplete
options={names}
onOpen={() => getSchoolList()}
loading={loading}
sx={{ width: 300 }}
renderInput={(params) => <TextField {...params} label="School Name" />}
/>

Related

React Select Async creatable doesn't save to the state

I am using react select async creatable,
the data from api loads correctly and can select it also can create new values
but after selecting a choice or if not, creating a new value, seems like my titleState becomes empty, I tried consoling the state but gives me blank/empty value on console
const [titleState,setTitleState] = useState('')
const loadOptions = (inputValue, callback) => {
axios.post(`sample/api`, {
data: inputValue
})
.then(res => {
callback(res.data.map(i => ({
label: i.title,
value: i.title,
})))
console.log(res)
})
.catch(err => console.log(err))
}
const handleInputChange = (newValue) => {
setTitleState(newValue)
}
const logState = () => {
console.log(titleState) // logs empty in the devtools
}
<AsyncCreatableSelect
menuPortalTarget={document.body}
styles={{ menuPortal: base => ({ ...base, zIndex: 9999 }) }}
loadOptions={loadOptions}
onInputChange={handleInputChange}
placeholder="Title Trainings"
/>
<Button onClick={logState}>Click</Button>
then I have some button when click will console the titleState, but it doesn't log it.
You should use onChange={handleInputChange} instead of onInputChange={handleInputChange}
onChange triggers when a new option is selected / created.
onInputChange triggers when writing a new option.

MUI Custom groupBy

I have built MUI grouped labels, but the moment I try to add the element into the state, the application crashes. Here's the minimal code.
const options = labels.map(option => {
return {
type: JSON.parse(localStorage.getItem("recentTags") as string).includes(option) ? "RECENT" : "ALL ",
labelText: option
};
});
<Autocomplete
multiple
disableClearable
filterSelectedOptions
groupBy={option => option.type}
isOptionEqualToValue={(option, value) => {
const labelText = value.labelText ? value.labelText : value;
return option.labelText.toUpperCase() === labelText.toUpperCase();
}}
value={value}
open={open}
onOpen={() => {
setOpen(true);
}}
onClose={() => {
setOpen(false);
}}
onChange={(_event, newValue) => {
console.log(newValue.map(el => el));
const latestLabel: any = newValue.slice(-1).pop();
const prevLabels = JSON.parse(localStorage.getItem("recentTags") as string);
if (!prevLabels.includes(latestLabel.labelText) && prevLabels.length < 5) {
localStorage.setItem("recentTags", JSON.stringify([...prevLabels, latestLabel.labelText]));
}
const newLabel = newValue.filter((x) => !labels.includes(x))[0];
setValue(newValue);
onSaveEcardLabels!(newValue, ecardItem.id);
if (!!newLabel) {
labels.push(newLabel.labelText);
}
}}
/>
I am storing recently used tags in localstorage, but I am confused in it's logic as well, I am not able to replace any newly recently used tag in local storage. I believe the problem lies in onChange event.
While onChange in newValue I get previous index and current Object, I would like only single array with index i.e. labelText.

React setState gives emty array in an axiosRequest

Hi I do have to following simplyfied code. I use Formik as a Validation. Also Material Ui and Reactjs. The Form, Row and Col Tags come from Material. The FastField is same as InputField.
What I want is onClick in the Inputfield a dropdown appears and shows an array which I fetched with the axios-Request.
ยดยดยด
const url = 'http://localhost:3000';
const [searchValues, setSearchValues] = useState([]);
const getDropdownItems = (event) => {
console.log('event', event.target.getAttribute('id'));
axios
.get(`${url}/${event.target.getAttribute('id')}`)
.then(
(res) => setSearchValues(res),
console.log('restl', searchValues)
);
};
render(
<Form
onFocus={getDropdownItems}
onSubmit={formik.handleSubmit}
>
<Row>
<Col xs="auto" style={minWidth}>
<FastField
id="DatumEingabe"
name="DatumEingabe"
component={Autocomplete}
label="Datum-Eingabe"
type="text"
options={searchValues}
/>
</Col>
</Row>
</Form>
)
When I check my console I get from the first console.log the name of
the Inputfield. The second console.log says the array is empty,
despite the res is available and should be set. Why does it not work
this way.
setSearchValues(res) will not update searchValues until the next render. If you want to log it each time it changes, you should instead do
const [searchValues, setSearchValues] = useState([]);
useEffect(() => {
console.log(searchValues);
}, [searchValues]);
const getDropdownItems = (event) => {
console.log('event', event.target.getAttribute('id'));
axios
.get(`${url}/${event.target.getAttribute('id')}`)
.then(
(res) => setSearchValues(res)
);
};
I don't think the change is made inmediatly. Try logging searchValues after a second or something like that to see if that is the problem.
const getDropdownItems = (event) => {
console.log('event', event.target.getAttribute('id'));
axios
.get(`${url}/${event.target.getAttribute('id')}`)
.then(
(res) => {
setSearchValues(res);
setTimeout(() => {
console.log('restl', searchValues);
}, 1000)
}
);
};
Also, you have the useEffect hook, which fires an event when a variable is change, so if you want to log it the second it changes you should use:
useEffect(() => {
console.log(searchValues);
}, [searchValues])
To acomplish that, remember to import:
import { useEffect } from "react";
or use
React.useEffect(...)

How to display data from the database in select option?

I can succesfully get the data from my database , but how can I display it Inside the Select?
This is where i want to display my data inside the select
<Select
fullWidth
value={newUsers}
onChange={handleChange}
>
<MenuItem value={0}>{newUsers.label}</MenuItem>
this is how i call the data from the database (this is working and I can see the data from my console)
const [newUserLists, setNewUserLists] =useState([]);
const newUsers= [];
const fetchData = async () => {
const response = await getreason();
response.data.map(function(u){
newUsers.push({
label: u.applicationcode,
value: u.applicationid
})
})
setNewUserLists(newUsers)
}
useEffect(() => {
fetchData();
}, [reRender]);
this is the result in console.log
Let's model this on the Material-UI Select tutorial and API doc page. There, we can see a few things:
value is the currently selected input value. It appears you're trying to set it to the list of objects that you read from the DB response, which is not correct. It is common practice to say something like the following:
const [selected, setSelected] = useState("");
const handleChange = (event) => {
setSelected(event.target.value);
};
return (
<FormControl>
<InputLabel>Selection</InputLabel>
<Select
value={selected}
onChange={handleChange}
>
{/* MenuItems go here */}
</Select>
</FormControl>
);
On an unrelated (to Material-UI) note, you seem to not actually use newUserLists in your code. I'm going to make the assumption that newUsers is just a placeholder to munge the data from the response into, but per #Naim-Mustafa's answer, it isn't needed and should not be used in your display.
Now, how do we use newUsersList to generate a list of MenuItems? Just as you've done elsewhere, map is the key:
{newUsersList.map(({ label, value }) => (
<MenuItem id={value} value={value}>
{label}
</MenuItem>
))}
Note that I'm assuming value is unique for the purposes of the id field. If it is not, replace with something more appropriate.
You can change const newUsers= []; to let newUsers= [];
but you dont have to use newUsers array at all, instead try using the state
const [newUserLists, setNewUserLists] =useState([]);
const [selectedOption, setSelectedOption] = useState();
const fetchData = async () => {
const response = await getreason();
setNewUserLists(response.data.map(user => ({
label: user.applicationcode,
value: user.applicationid})))
}
useEffect(() => {
fetchData();
}, [reRender]);
return (
<>
<select value={selectedOption}
onChange={(event) => setSelectedOption(event.target.value)}
>
{newUserLists
.map(user =>
<option key={user.label} value={user.label}>
{user.label}</option>}
</select>
</>

React use state hook not updating

I am loading data on the initial load. When they user clicks the button to add a recognition, the api call adds it, and returns it. I add the new post to the array, but the new update doesn't render. The return object, and the array of objects are the same object type. When I reload the page, the new post is rendered, just not on the add function. Is there something that I am missing?
const [recognitions, setRecognitions] = useState([]);
useEffect(() => {
Api.GetRecognitions(params)
.then(response => {
const items = response || [];
setRecognitions(recognitions => [...recognitions, ...items]);
})
}, [setRecognitions]);
const handleAddPost = () => {
Api.AddRecognition(params)
.then(response => {
const newPost = response;
setRecognitions(recognitions=> [...recognitions, newPost])
});
}
<Form.Group>
<Form.Field>
<Button basic color='blue' onClick={handleAddPost}>Add</Button>
</Form.Field>
</Form.Group>
<Form.Group>
<Form.Field>
{recognitions.map(recognition => (
<RecogWallPost
key={recognition.recogStagingId}
recognition={recognition}
participantId={participantId}
/>
)
)}
</Form.Field>
</Form.Group>
Instead of passing [setRecognitions] as the second argument to useEffect, you want to pass [recognitions]. This tells the useEffect hook to run every time recognitions changes, which it does inside handleAddPost.
You have to create an async function, and then use it as follow:
useEffect(() => {
async function initData() {
Api.GetRecognitions(params)
.then(response => {
const items = response || [];
setRecognitions(recognitions => [...recognitions, ...items]);
})
}
initData()
}, [setRecognitions]);

Resources