如何在material-ui/SelectField组件中启用全选功能?

6

文档链接 我正在按照上述文档链接实现Select-field组件。 我没有找到这个组件中选择全部的正确文档。

导入该组件的语句

import SelectField from 'material-ui/SelectField'; 

组件代码:

<SelectField
    className="search_items"
    multiple={true}
    hintText="Select Item"
    value={values}
    onChange={this.handleChange} >
    {this.menuItems(values)}
 </SelectField>

菜单项功能:

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函数:

handleChange(event, index, values) {
    this.setState({ values })
}

如何启用“全选”选项以选择所有项目。 提前感谢。
5个回答

14

创建一个带有multiple属性和选项Select AllSelect

就像单个选择一样,可以通过在onChange回调中访问event.target.value获取新值。它始终是一个数组。当单击Select All时,在数组的最后一个索引中会出现值all(在此示例中),该值可用于切换选择所有或取消选择所有选项。

*此示例中的选项前缀有复选框。

这里是在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>

这个解决方案在我的情况下完美运行。 - Sivakumar A

5
在所有选项上方创建一个 MenuItem

<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>

创建一个状态 checkedAll,每当单击 Select All 项目时更新该状态。每当单击 SelectAll 菜单项时,使用一个函数将值更新为所需的数据(这里是唯一的)。

selectAll = () => {
    if(this.state.checkedAll)
      this.setState(
        {values:[]}
      );
    else
      this.setState(
        {values:names}
      );
    this.setState({
      checkedAll:!this.state.checkedAll
    });
  }


当我点击“全选”时,首次从值中选择所有项目时,所有项目都未被选中,显示为“未选择任何项”,然后第二次再选择“全选”时,所有项目都会被选中。 - user9883888
在selectAll函数中,第一行应该是if(!this.state.checkedall)。如果是这种情况,它会起作用。 - user9883888
1
Material UI - MenuItem 组件截止至今日(2019-12-12),不支持包括 onClick 在内的事件,因此该解决方案不起作用。 我发现 ListItemText 具有可嵌套到 MenuItem 组件的 onClick 事件 - 如 https://material-ui.com/components/selects/#multiple-select - "tag" 菜单所示。 虽然由于某种原因,将其与 Select 组件的 onChange 事件组合使用会导致其表现出奇怪的行为,并且无法从 onClick 的处理中触发任何钩子。 - Gergely M

1
@Bhalahariharan V的解决方案很好,但没有考虑到输入值可能为all的情况。因此最好将属性data-button-all添加到Select all菜单项中。
然后,在handle change函数中,检查此属性以确定是否已按下选择all按钮。
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>

1

我成功地让被采纳的答案运行良好。因此,请在阅读本文之前参考anonymous_siva的答案。

是的,您不能使组件处理事件而没有不愉快的副作用。但是,您可以通过像这样的事件将事件处理从父级移动到子级:

<MenuItem key={'Select all'}>
  <ListItemText
    primary="Select all"
    onClick={(event) => {
      event.stopPropagation();
      setValues(values);
    }}
  />
</MenuItem>

这里你可以看到,我们需要停止传播并使用所有可用的默认选项更新组件状态。
您可以完全按照取消选择所有选项的方式进行操作,但将状态更改为空。
现在,您需要手动覆盖MenuItem的边距和填充为零,并使子组件使用填充占据所需位置。这将确保子元素占据父元素的所有内部空间。

0
如评论所述,已接受的答案不再适用。这仍然是一个好方法,但您必须从MUI Select组件中取消multiple选项,并在Select上实现一个handleChange来处理从列表中添加/删除单个项目。
<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);
    }
  };

建议的答案是基于 before hooks 的,所以我没有完全更新它,但你可以理解其中的思路。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接