javascript - Multiselect in a dropdown list in React - Stack Overflow

I am trying to be able to multi select different values from a dropdown I created. So the following cod

I am trying to be able to multi select different values from a dropdown I created. So the following code is actually showing the names of the people but I would like to be able to select more than one.

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

I am trying to be able to multi select different values from a dropdown I created. So the following code is actually showing the names of the people but I would like to be able to select more than one.

<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>
Share Improve this question edited Jun 25, 2020 at 18:02 JuanCaicedo 3,4583 gold badges20 silver badges37 bronze badges asked Jun 19, 2020 at 4:34 user234user234 591 gold badge1 silver badge5 bronze badges 1
  • Are you using react-bootstrap? – JuanCaicedo Commented Jun 20, 2020 at 21:00
Add a ment  | 

3 Answers 3

Reset to default 1

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. For the value, set the default state as an array. For the onChange, we are going to set it where whenever the item is checked, it sets a new state so like this:

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. 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 ponent,

  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

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 plete code for the parent 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 ponent
 * @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 ponent
 * @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)

Answer

You will need to pass another prop to Form.Control to specify that you would like your select to allow multiple selections. You can do this either as multiple={true}, or as the shorthand multiple (both are equivalent).

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. Forms are notoriously challenging because they involve a lot of internal state.

Other things to try

  • Use react hooks to manage state instead of a class ponent. This can make it easier to work with state, in my opinion

Bug in my example

  • When there is only one selection and you try to deselect it, the onChange event is not trigged. I'm not sure why that's happening here

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745275258a4619999.html

相关推荐

  • javascript - Multiselect in a dropdown list in React - Stack Overflow

    I am trying to be able to multi select different values from a dropdown I created. So the following cod

    8小时前
    20

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信