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
3 Answers
Reset to default 1It 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
评论列表(0条)