简体   繁体   English

在 React 的下拉列表中进行多选

[英]Multiselect in a dropdown list in React

I am trying to be able to multi select different values from a dropdown I created.我试图能够从我创建的下拉列表中多 select 不同的值。 So the following code is actually showing the names of the people but I would like to be able to select more than one.所以下面的代码实际上是显示人的名字但我希望能够 select 不止一个。

<Form.Group controlId="exampleForm.ControlSelect4">
    <Form.Label> Names </Form.Label>
    <Form.Control as="select" value={this.state.selectedNames} 
                  onChange={this.updateTable}>
        {this.state.names.map((name) => <option key={name.value} value={name.value}> {name.display } </option>)}
    </Form.Control>
</Form.Group>

It is similar to setting a single value but instead, the value is an array instead of a string or a number.它类似于设置单个值,但取而代之的是,该值是一个数组,而不是字符串或数字。

First, you have to change what the value and onChange function are doing.首先,您必须更改 value 和 onChange function 正在做什么。 For the value, set the default state as an array.对于该值,将默认 state 设置为数组。 For the onChange , we are going to set it where whenever the item is checked, it sets a new state so like this:对于onChange ,我们将在每次检查项目时将其设置为新的 state ,如下所示:

javascript javascript

state = {
 selectedNames:[]
}

onChange = (e) => {
  e.preventDefault()
  this.setState(prevState => ({selectedNames: [...prevState.selectedNames, e.target.value]})
}

Hopefully, this helps!希望这会有所帮助!

The event needs to be added to individual option, multi select takes quite a bit of lines to implement.该事件需要添加到单个选项中,多 select 需要相当多的行来实现。 Here's some snippet just for the sections you might care.这是您可能关心的部分的一些片段。 I'm not using any third party controls as you can see.如您所见,我没有使用任何第三方控件。

      <div className="_action">
        <span
          role="button"
          aria-pressed="false"
          tabIndex={0}
          onClick={() => { onClear() }}
        >
          Clear Selection
        </span>
      </div>
      {options.map(option => (
        <div
          role="presentation"
          className="_item"
          key={option.value}
          onClick={() => { onSelect(option.value) }}
        >
          <Checkbox value={isChecked(option, value)} />
          <span className="_label">{option.label}</span>
        </div>
      ))}

The onSelect and onClear might be provided from parent/self component, onSelectonClear可能由 parent/self 组件提供,

  const onSelect = useCallback(v => {
    const e = {
      target: {
        name,
        value: toggleValueInOptions(value, v, options)
      }
    }
    onChange(e)
  }, [name, value, options, onChange])

  const onClear = useCallback(() => {
    const e = { target: { name, value: [] } }
    onChange(e)
  }, [name, onChange])

and a utility function toggleValueiInOptions和一个实用程序 function toggleValueiInOptions

const toggleValueInOptions = (value, key, options) => {
  if (!value) return []

  const values = value.slice()
  const index = values.indexOf(key)
  if (index >= 0) {
    values.splice(index, 1)
  } else {
    values.push(key)
  }

  if (!options) return values

  return options.reduce((acc, option) => {
    if (values.includes(option.value)) {
      acc.push(option.value)
    }
    return acc
  }, [])
}

export default toggleValueInOptions

============== ===============

For your reference, this is the complete code for the parent MultiSelect .供您参考,这是父MultiSelect的完整代码。

import React, { useState, useCallback, useRef } from 'react'
import PropTypes from 'prop-types'
import { useClickOutside } from '../../utils'
import InputBase from '../InputBase'
import Pills from './Pills'
import MultiSelection from './MultiSelection'
import MultiSelectStyle from './MultiSelectStyle'
import SelectIcon from './SelectIcon'
import { optionsType, valuesType } from './optionsType'
import toggleValueInOptions from './toggleValueInOptions'
import valueToItems from './valueToItems'
import SelectionSummary from './SelectionSummary'

/**
 * @memberof MultiSelect
 * @param {Object} _                Props
 * @param {elementType} _.Style       Style component
 * @param {string} _.name             Input name
 * @param {valueType[]} _.value         Input value of array
 * @param {func} _.onChange           Value change event
 * @param {optionsType[]} _.options     Options array
 * @param {elementType} _.Selection=MultiSelection    Component for dropdown selection
 * @param {bool} _.disabled=false     Input disabled flag
 * @param {bool} _.width=auto         Input width
 * @param {string} _.placeholder      Input placeholder
 * @param {elementType} _.DropdownIcon=DropdownIcon   Compoent for dropdown icon component
 * @param {number} _.pillVisibleMax   Max pill displayed
 * @param {elementType} _.Summary=SelectionSummary    Component for dropdown summary
 */
const MultiSelect = ({
  Style, name, value, options, onChange,
  Selection, disabled, width, placeholder,
  DropdownIcon, pillVisibleMax, Summary,
  ...props
}) => {
  const [focus, setFocus] = useState(false)

  const onExpand = useCallback(() => {
    if (!disabled) setFocus(true)
  }, [disabled])
  const onCollapse = useCallback(() => { setFocus(false) }, [])
  const ref = useRef()
  useClickOutside({ ref, handler: () => { onCollapse() } })

  const onSelect = useCallback(v => {
    const e = {
      target: {
        name,
        value: toggleValueInOptions(value, v, options)
      }
    }
    onChange(e)
  }, [name, value, options, onChange])

  const onClear = useCallback(() => {
    const e = { target: { name, value: [] } }
    onChange(e)
  }, [name, onChange])

  const after = <DropdownIcon focus={focus} onExpand={onExpand} onCollapse={onCollapse} />

  const phText = value.length ? '' : placeholder
  const vText = (value.length > pillVisibleMax) ? `${value.length} Selected` : ''

  return (
    <Style ref={ref}>
      <InputBase
        value={vText}
        placeholder={phText}
        disabled={disabled}
        readOnly
        after={after}
        onFocus={onExpand}
        width={width}
        {...props}
      />
      {!vText && (
        <Pills
          items={valueToItems(value, options)}
          onSelect={onSelect}
          disabled={disabled}
        />
      )}
      {focus && (
        <Selection
          value={value}
          options={options}
          onSelect={onSelect}
          onClear={onClear}
          Summary={Summary}
        />
      )}
    </Style>
  )
}

MultiSelect.propTypes = {
  Style: PropTypes.elementType,
  name: PropTypes.string,
  value: valuesType,
  options: optionsType,
  onChange: PropTypes.func,
  Selection: PropTypes.elementType,
  disabled: PropTypes.bool,
  width: PropTypes.string,
  placeholder: PropTypes.string,
  DropdownIcon: PropTypes.elementType,
  pillVisibleMax: PropTypes.number,
  Summary: PropTypes.elementType
}

MultiSelect.defaultProps = {
  Style: MultiSelectStyle,
  name: '',
  value: [],
  options: [],
  onChange: () => { },
  Selection: MultiSelection,
  disabled: false,
  width: '',
  placeholder: '',
  DropdownIcon: SelectIcon,
  pillVisibleMax: 99,
  Summary: SelectionSummary
}

export default MultiSelect

(I'm assuming you are using react-bootstrap ) (我假设您正在使用react-bootstrap

Answer回答

You will need to pass another prop to Form.Control to specify that you would like your select to allow multiple selections.您需要将另一个道具传递给Form.Control以指定您希望 select 允许多项选择。 You can do this either as multiple={true} , or as the shorthand multiple (both are equivalent).您可以将其作为multiple={true}或作为速记multiple (两者是等效的)来执行此操作。

This example in their docs uses a multiselect, that might be helpful.他们文档中的这个示例使用了多选,这可能会有所帮助。

I put together this sandbox which might illustrate how to use it.我把这个沙盒放在一起,可以说明如何使用它。

What's tricky有什么棘手的

Handling state with react can be hard.用反应处理 state 可能很难。 Forms are notoriously challenging because they involve a lot of internal state. Forms 是出了名的具有挑战性,因为它们涉及很多内部 state。

Other things to try其他要尝试的事情

  • Use react hooks to manage state instead of a class component.使用反应挂钩来管理 state 而不是 class 组件。 This can make it easier to work with state, in my opinion在我看来,这可以使使用 state 变得更容易

Bug in my example我的例子中的错误

  • When there is only one selection and you try to deselect it, the onChange event is not trigged.当只有一个选择并且您尝试取消选择它时,不会触发onChange事件。 I'm not sure why that's happening here我不确定为什么会在这里发生

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM