user9883888
user9883888

Reputation: 419

How to enable select all feature in material-ui/SelectField component?

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

Answers (5)

TheKalashnikov
TheKalashnikov

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

Bhala Hariharan
Bhala Hariharan

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

Andrew Tytenko
Andrew Tytenko

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

repinuj
repinuj

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

shiva
shiva

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

Related Questions