Reputation: 419
Document Link I am following the above document Link for implementing the Select-field component. I didnot find the proper document for select all in this component.
Import statement for component
import SelectField from 'material-ui/SelectField';
Component code:
<SelectField
className="search_items"
multiple={true}
hintText="Select Item"
value={values}
onChange={this.handleChange} >
{this.menuItems(values)}
</SelectField>
menuItems Function:
menuItems(values) {
return unique && unique.map((name) => (
<MenuItem
key={name}
insetChildren={true}
checked={values && values.indexOf(name) > -1}
value={name}
primaryText={name && name.concat('(').concat(sectors.filter(i => i === name).length).concat(')')}
/>
));
}
OnChange Function :
handleChange(event, index, values) {
this.setState({ values })
}
How to enable select all option for all the items to be selected. Thanks in advance
Upvotes: 7
Views: 23101
Reputation: 391
The solution of @Bhalahariharan V is good but does not take into account inputs that would have the value all
. It would be thus better to add a property data-button-all
to the Select all
menu item.
Then, in the handle change
function, check for this property to know if the select all
button has been pressed or not.
const [selected, setSelected] = useState([]);
const handleChange = (event) => {
const value = event.target.value.filter((val) => !!val);
const isClickAll = !!(event.currentTarget as any).getAttribute('data-button-all');
if (isClickAll) {
setSelected(selected.length === options.length ? [] : options);
return;
}
setSelected(value);
};
<Select
multiple
value={selected}
onChange={handleChange}
renderValue={(selected) => selected.join(", ")}
>
<MenuItem data-button-all>
<ListItemIcon>
<Checkbox
checked={options.length > 0 && selected.length === options.length}
indeterminate={selected.length > 0 && selected.length < options.length}
/>
</ListItemIcon>
<ListItemText primary="Select All" />
</MenuItem>
{options.map((option) => (
<MenuItem key={option} value={option}>
<ListItemIcon>
<Checkbox checked={selected.indexOf(option) > -1} />
</ListItemIcon>
<ListItemText primary={option} />
</MenuItem>
))}
</Select>
Upvotes: 1
Reputation: 296
Create a Select
with multiple
property and an option Select All
along with other options.
Like with the single selection, you can pull out the new value by accessing event.target.value
in the onChange
callback. It's always an array. When Select All
is clicked, the value all
(in this example) will be present in the last index of the array which can be used to toggle select all or unselect all options.
*This example has a checkbox prefixed in the options.
Here's the link to the working demo in codesandbox.
const [selected, setSelected] = useState([]);
const handleChange = (event) => {
const value = event.target.value;
if (value[value.length - 1] === "all") {
setSelected(selected.length === options.length ? [] : options);
return;
}
setSelected(value);
};
<Select
multiple
value={selected}
onChange={handleChange}
renderValue={(selected) => selected.join(", ")}
>
<MenuItem value="all">
<ListItemIcon>
<Checkbox
checked={options.length > 0 && selected.length === options.length}
indeterminate={selected.length > 0 && selected.length < options.length}
/>
</ListItemIcon>
<ListItemText primary="Select All" />
</MenuItem>
{options.map((option) => (
<MenuItem key={option} value={option}>
<ListItemIcon>
<Checkbox checked={selected.indexOf(option) > -1} />
</ListItemIcon>
<ListItemText primary={option} />
</MenuItem>
))}
</Select>
Upvotes: 14
Reputation: 21
I managed to make the accepted answer work well. So please refer to the answer of anonymous_siva before reading this.
So yes, you can't make the component handle events without unpleasant side effects. But you can remove event handling from to a child with an event like this:
<MenuItem key={'Select all'}>
<ListItemText
primary="Select all"
onClick={(event) => {
event.stopPropagation();
setValues(values);
}}
/>
</MenuItem>
Here you can see that we need to stop propagation and update your component's state with all default options that are available.
You can do exactly the same for deselect all option, but change state to being empty.
Now, you need to manually override margins and paddings of MenuItem to zero, and make the child component take the place it needs using the padding. This will make sure that children occupies all the insides of the parent.
Upvotes: 1
Reputation: 26
As commented, the accepted answer no longer works. It's still a good approach, but you have to take off the multiple
option from the MUI Select
component, and implement a handleChange
on the Select
that handles single items being added/removed from the list.
<Select
className="search_items"
hintText="Select Item"
value={values}
onChange={handleChange}
>
<MenuItem
value="all"
/>
{this.menuItems(values)}
</SelectField>
const handleChange = selection => {
if (selection === "all") {
if (selected.length === options.length) {
setSelected([]);
} else {
setSelected(options);
}
} else {
let newSelected;
if (selected.map(s => s.id).includes(selection.id)) {
newSelected = selected.filter(s => s.id !== selection.id);
} else {
newSelected = [...selected, selection];
}
setSelected(newSelected);
}
};
The suggested answer is from before hooks, so I didn't totally update it, but you get the idea.
Upvotes: 0
Reputation: 3941
Create a MenuItem
above all the choices.
<SelectField
multiple={true}
hintText="Multiple Select"
value={values}
onChange={this.handleChange}
>
<MenuItem
checked={this.state.open}
value="Select all"
onClick={this.selectAll}
primaryText={checkedAll?"Select None":"Select all"}
/>
{this.menuItems(values)}
</SelectField>
Create a state checkedAll
which is updated whenever the Select All
item is clicked. Whenever the SelectAll
MenuItem is clicked update the values to the required data(here unique) using a function.
selectAll = () => {
if(this.state.checkedAll)
this.setState(
{values:[]}
);
else
this.setState(
{values:names}
);
this.setState({
checkedAll:!this.state.checkedAll
});
}
Upvotes: 6