I am trying to set the selected prop with react mui menu item. I have a multiple select menu list, where I have a field allValues, that on clicking it, toggles the selection of all menu items. And that part works just fine. The code looks like this:
<Select
multiple
value={selectedValues.map(klasse => klasse.id)}
onChange={(event) => handleChange(event.target.value, onChange, idToValues)}
input={<Input id="select-multiple-chip"/>}
classes={{root: classes.select}}
renderValue={selectedIds => (
<div className={classes.chips}>
{selectedIds.map(classId => (
<Chip
key={classId}
label={idToValues[classId] && idToValues[classId].classCode}
className={classes.chip}
onDelete={(event) => onChange(selectedValues.filter(class => class.id !== classId))}/>
))}
</div>
)}
MenuProps={MenuProps}
>
{!!allValues.length &&
<MenuItem value="allValues" selected={allValues.length === selectedValues.length}>
All classes
</MenuItem>
}
{allValues.map(class => (
<MenuItem key={class.id} value={class.id}>
{class.classCode}
</MenuItem>
))}
</Select>
I can see in the dev tools that allValues and selectedValues are of the equal length, but the selected prop is still false. How is that possible, and how can I fix this?
Try adding () brackets like:
selected={(allValues.length === selectedValues.length)}
Related
I have given unique key to every item but it still shows Each child in a list should have a unique "key" prop.
<FormControl className="registerInputs">
<InputLabel htmlFor="name-multiple">Country</InputLabel>
<Select
value={country}
placeholder="Country"
input={<Input id="name-multiple" />}
onChange={(e) => selectCountryHandler(e.target.value)}
>
{!!countryArr?.length &&
countryArr.map(({ label, value }) => (
<MenuItem key={label} value={value}>
{label}
</MenuItem>
))}
</Select>
</FormControl>;
As I can see in your code, you have allotted the label as a key. I wonder if there are more than one similar labels that are giving you an error. I would suggest you use
countryArr.map(({ label, value }, id) => (
<MenuItem key={id} value={value}>
{label}
</MenuItem>
))
Please try this and do tell me if it is working or not.
I am trying to use Material UI multiselect with checkboxes. So far, i am able to make multiple selects and get the values but i am unable to render the actual names of selected values or get all selected values. Any leads to a new approach i can use or useful links to help get the ids of all selected values in my array will be appreciated.
I created a sandbox that has a mock of my data from an api as well here : sandbox
My select looks like this :
const [selected, setSelected] = useState([]);
const isAllSelected =
options.length > 0 && selected.length === options.length;
const handleChange = (event) => {
console.log("vals", event.target);
const value = event.target.value;
if (value[value.length - 1] === "all") {
setSelected(selected.length === options.length ? [] : options.title);
return;
}
setSelected(value);
console.log("values", selected);
};
<FormControl className={classes.formControl}>
<InputLabel id="mutiple-select-label">Multiple Select</InputLabel>
<Select
labelId="mutiple-select-label"
multiple
variant="outlined"
value={selected}
onChange={handleChange}
renderValue={(selected) => selected}
MenuProps={MenuProps}
>
<MenuItem
value="all"
classes={{
root: isAllSelected ? classes.selectedAll : ""
}}
>
<ListItemIcon>
<Checkbox
classes={{ indeterminate: classes.indeterminateColor }}
checked={isAllSelected}
indeterminate={
selected.length > 0 && selected.length < options.length
}
/>
</ListItemIcon>
<ListItemText
classes={{ primary: classes.selectAllText }}
primary="Select All"
/>
</MenuItem>
{options.map((option) => (
<MenuItem key={option.id} value={option.id}>
<ListItemIcon>
<Checkbox checked={selected.includes(option.id)} />
</ListItemIcon>
<ListItemText primary={option.title} />
</MenuItem>
))}
</Select>
<p>{selected}</p>
</FormControl>
I did a few fix in your code so it works, in this sandbox:
To display some text in your menu, you are supposed to display the text in the component ListItemText:
<ListItemText>{option}</ListItemText>
An other thing is that you cannot access selected directly, since it is a state, so it is set asynchronously. To solve this, you can simply access it like this:
selected?.length
This way, even if selected is still undefined, it will not throw any errors
I have a list of users and a Select dropdown from material UI with some values. I am able to console.log the values of the select but how can I know to which user in the List they refer to?
<List>
{userList.map((user:any) => (
<ListItem key={user.key}>
<ListItemAvatar>
<Avatar>
<PersonIcon />
</Avatar>
</ListItemAvatar>
<ListItemText primary={user.name} />
<Select
value={userValue}
onChange={handleChange}
>
{dropdownvalues.map(
(g: { value: string}) => (
<MenuItem key={g.value} value={g.value}>
{g.value}
</MenuItem>
)
)}
</Select>
</ListItem>
))}
</List>
const handleChange=(e:any,index:any) => {
console.log(e.target.value)//here I am able to console log just the value how can I bind the user too given the fact that this funciton doesnt accept another parameter
}
Just add index as value as it is uniquely identifiable in the following code -
{dropdownvalues.map(
(g: { value: string},index:number) => (
<MenuItem key={g.value} value={index}>
{g.value}
</MenuItem>
)
)}
After that just access your selected user as -
const handleChange = (e:any) => {
const selectedInd = e.target.value;
console.log('index->',selectedInd);
console.log(dropdownvalues[e.target.value]);
}
Simplest way is to extend your handleChange function and call like this:
// ...
onChange={(evt) => handleChange(user)}
// ... And then extend the function:
const handleChange=(user:any) => {
console.log(user)
}
The Material UI documentation includes an example of a multiple select where the selected options are rendered with the Chip component by using the renderValue prop on the Select. The standard behavior for the Select component is that clicking on the current value opens the list of options.
I am trying to tweak this so that the Chips show the X button, and clicking on the X should instantly remove that item from the selections rather than opening the options list.
That seems easy, but I can't get the onDelete event of the Chip to fire. Clicking the X still just opens the Select.
How can I get the onDelete event to take priority? From what I know about event bubbling, it seems like the Chip should handle the event first.
Code Sandbox Demo
Code:
const MultipleSelectDemo = () => {
const [personName, setPersonName] = React.useState<string[]>(initialSelected);
const handleChange = (event: React.ChangeEvent<{ value: unknown }>) => {
setPersonName(event.target.value as string[]);
};
// this never gets called
const handleDelete = (e: React.MouseEvent, value: string) => {
e.preventDefault();
console.log("clicked delete");
setPersonName((current) => _without(current, value));
};
return (
<div>
<FormControl>
<InputLabel id="demo-mutiple-chip-checkbox-label">
Chip + Check
</InputLabel>
<Select
labelId="demo-mutiple-chip-checkbox-label"
id="demo-mutiple-chip-checkbox"
multiple
value={personName}
onChange={handleChange}
onOpen={() => console.log("select opened")}
IconComponent={KeyboardArrowDownIcon}
renderValue={(selected) => (
<div>
{(selected as string[]).map((value) => (
<Chip
key={value}
label={value}
clickable
className={classes.chip}
onDelete={(e) => handleDelete(e, value)}
onClick={() => console.log("clicked chip")}
/>
))}
</div>
)}
>
{names.map((name) => (
<MenuItem key={name} value={name}>
<Checkbox checked={personName.includes(name)} />
<ListItemText primary={name} />
</MenuItem>
))}
</Select>
</FormControl>
</div>
);
}
The opening of the Select is triggered by the mouse-down event -- not the click event.
You can get your desired behavior by stopping propagation of the mouse-down event when it occurs on the delete icon of the Chip:
<Chip
key={value}
label={value}
clickable
deleteIcon={
<CancelIcon
onMouseDown={(event) => event.stopPropagation()}
/>
}
className={classes.chip}
onDelete={(e) => handleDelete(e, value)}
onClick={() => console.log("clicked chip")}
/>
For people who still find answer for this question, MUI has a component does exactly what you want: Autocomplete, you can find it here: https://mui.com/material-ui/react-autocomplete/
Here is the code example from MUI documents: Code Sandbox Demo
Hello guys I'm using React Material UI select. When I change option I trigger onChange method and add attr on selected value so how can I set fisrt option of items as selected.
value={} **// I want to display first option to selected without trigger on Change method**
onChange={(e) => {
data.forEach(a => {
if (a.Id === e.target.value) {
a.selected = true
} else {
a.selected = false
}
});
}}
>
<MenuItem disabled value=""><em>Please Select</em></MenuItem>
{data.map((item) => {
return (
<MenuItem key={item.Id} value={item.Id} >
{item.Ad}
</MenuItem>
);
})}
</Select>
You need 2 states on your component, data and active. Where data is the items you want to display on the dropdown, and active which indicates what item is currently selected. Commonly, we use useEffect hook to initialize states.
Also, wehave to re-implement your onChange function. I suggest you review the docs on how to update states on functional component https://reactjs.org/docs/hooks-reference.html#usestate.
Anyway, you can change your code to this
export default function App() {
const [data, setData] = React.useState(DATA);
// select the first option by default
const [active, setActive] = React.useState(DATA[0].Id);
function onChange(event) {
setActive(event.target.value);
}
return (
<Select value={active} onChange={onChange} fullWidth>
<MenuItem disabled value="">
<em>Please Select</em>
</MenuItem>
{data.map((item) => (
<MenuItem key={item.Id} value={item.Id}>
{item.Ad}
</MenuItem>
))}
</Select>
);
}
...and I created a codesandbox for you to try it out.