多选作为按钮组
Multiselect as a Button Group
我一直在努力寻找 redux 形式的具有多个值的字段的最佳实践。
这就是我想要完成的。
那些按钮是自定义组件。我让它在视觉上工作,使用自定义组件和 onChange
来更新隐藏复选框字段的 redux 值。
这似乎是一个相当常见的用例,因为它本质上是一个多选。我知道文档 roccomend 使用 react-widgets multiselect 但它似乎不适合我试图完成的按钮组样式。这是我到目前为止所拥有的,但是将 redux-form 视图复选框视为布尔值而不是数组,我认为这对我不起作用。
import React, {Component} from 'react'
import {Field} from 'redux-form'
import * as icons from './../MultiSelectBtnGrid/icons'
const btnStyles = {
border: '3px solid #f6e9db',
background: 'transparent',
borderRadius: '45px',
width: '250px'
}
const btnSelectedStyles = {
border: '3px solid #27313c',
background: 'transparent',
borderRadius: '45px',
width: '250px'
}
class MultiSelectField extends Component {
constructor(props) {
super(props)
this.state = {selected: false}
this.handleClick = this.handleClick.bind(this)
}
handleClick() {
this.setState({selected: !this.state.selected})
this.props.input.onChange(!this.state.selected)
}
render() {
const {content, idx, input: {name}} = this.props
const {selected} = this.state
return (
<div className={'row m-auto rel'}>
<button type={'button'} className={`mb-1 p-3 ml-auto mr-auto`} style={selected ? btnSelectedStyles : btnStyles}
onClick={this.handleClick}>
{content}
<span style={{position: 'absolute', right: '15px', top: '0', bottom: '0', margin: 'auto'}}
className={'mb-1 d-flex justify-content-center align-items-center'}>{icons.plusIcon(selected)}</span>
</button>
<input type={'checkbox'} name={`${name}`} value={selected ? 'test' : null} checked={selected} />
</div>
)
}
}
export default class MultiSelectBtnGroup extends Component {
constructor(props) {
super(props)
this.state = {selected: props.formState.values[props.name]}
}
render() {
const {options, name} = this.props
return (
<div className={'container'}>
<div className={'row'}>
{options.map((option, idx) => {
return <Field
component={MultiSelectField}
name={name}
type='checkbox'
content={option.content}
key={idx}
{...this.props}
className={'col'}
idx={idx}/>
})}
</div>
</div>
)
}
}
MultiSelectBtnGroup
应该是 Field
的组件,使值成为表单状态中的数组。
这是一个例子:
const MultiSelectBtnGroup = { input, options } => {
const values = input.value || [];
const handleClick = (value, select) => {
var index = values.indexOf(value);
if (select) {
if (index === -1) {
input.onChange([...values, value]);
}
} else {
if (index !== -1) {
input.onChange(values.filter(v => v !== value));
}
}
};
return (
<div className="row">
{options.map(o => {
const selected = values.indexOf(o.value) !== -1;
return (
<div className="col">
<div className="row m-auto rel">
<button
type="button"
className="mb-1 p-3 ml-auto mr-auto"
style={selected ? btnSelectedStyles : btnStyles}
onClick={e => handleClick(o.value, !selected)}
>
{o.content}
<span
style={{ position: 'absolute', right: '15px', top: 0, bottom: 0, margin: 'auto' }}
className="mb-1 d-flex justify-content-center align-items-center"
>
{icons.plusIcon(selected)}
</span>
</button>
<input
type="hidden"
name={name}
value={o.value}
checked={selected}
/>
</div>
</div>
);
})}
</div>
);
};
const Example = { options, name } => (
<div className="container">
<Field component={MultiSelectField} name={name} />
</div>
);
<input>
不需要在那里维护表单状态,但如果您想以传统方式提交表单,它会很有帮助。
我一直在努力寻找 redux 形式的具有多个值的字段的最佳实践。
这就是我想要完成的。
那些按钮是自定义组件。我让它在视觉上工作,使用自定义组件和 onChange
来更新隐藏复选框字段的 redux 值。
这似乎是一个相当常见的用例,因为它本质上是一个多选。我知道文档 roccomend 使用 react-widgets multiselect 但它似乎不适合我试图完成的按钮组样式。这是我到目前为止所拥有的,但是将 redux-form 视图复选框视为布尔值而不是数组,我认为这对我不起作用。
import React, {Component} from 'react'
import {Field} from 'redux-form'
import * as icons from './../MultiSelectBtnGrid/icons'
const btnStyles = {
border: '3px solid #f6e9db',
background: 'transparent',
borderRadius: '45px',
width: '250px'
}
const btnSelectedStyles = {
border: '3px solid #27313c',
background: 'transparent',
borderRadius: '45px',
width: '250px'
}
class MultiSelectField extends Component {
constructor(props) {
super(props)
this.state = {selected: false}
this.handleClick = this.handleClick.bind(this)
}
handleClick() {
this.setState({selected: !this.state.selected})
this.props.input.onChange(!this.state.selected)
}
render() {
const {content, idx, input: {name}} = this.props
const {selected} = this.state
return (
<div className={'row m-auto rel'}>
<button type={'button'} className={`mb-1 p-3 ml-auto mr-auto`} style={selected ? btnSelectedStyles : btnStyles}
onClick={this.handleClick}>
{content}
<span style={{position: 'absolute', right: '15px', top: '0', bottom: '0', margin: 'auto'}}
className={'mb-1 d-flex justify-content-center align-items-center'}>{icons.plusIcon(selected)}</span>
</button>
<input type={'checkbox'} name={`${name}`} value={selected ? 'test' : null} checked={selected} />
</div>
)
}
}
export default class MultiSelectBtnGroup extends Component {
constructor(props) {
super(props)
this.state = {selected: props.formState.values[props.name]}
}
render() {
const {options, name} = this.props
return (
<div className={'container'}>
<div className={'row'}>
{options.map((option, idx) => {
return <Field
component={MultiSelectField}
name={name}
type='checkbox'
content={option.content}
key={idx}
{...this.props}
className={'col'}
idx={idx}/>
})}
</div>
</div>
)
}
}
MultiSelectBtnGroup
应该是 Field
的组件,使值成为表单状态中的数组。
这是一个例子:
const MultiSelectBtnGroup = { input, options } => {
const values = input.value || [];
const handleClick = (value, select) => {
var index = values.indexOf(value);
if (select) {
if (index === -1) {
input.onChange([...values, value]);
}
} else {
if (index !== -1) {
input.onChange(values.filter(v => v !== value));
}
}
};
return (
<div className="row">
{options.map(o => {
const selected = values.indexOf(o.value) !== -1;
return (
<div className="col">
<div className="row m-auto rel">
<button
type="button"
className="mb-1 p-3 ml-auto mr-auto"
style={selected ? btnSelectedStyles : btnStyles}
onClick={e => handleClick(o.value, !selected)}
>
{o.content}
<span
style={{ position: 'absolute', right: '15px', top: 0, bottom: 0, margin: 'auto' }}
className="mb-1 d-flex justify-content-center align-items-center"
>
{icons.plusIcon(selected)}
</span>
</button>
<input
type="hidden"
name={name}
value={o.value}
checked={selected}
/>
</div>
</div>
);
})}
</div>
);
};
const Example = { options, name } => (
<div className="container">
<Field component={MultiSelectField} name={name} />
</div>
);
<input>
不需要在那里维护表单状态,但如果您想以传统方式提交表单,它会很有帮助。