如何为 'react-select' 实施字段验证
How do I implement field validation for 'react-select'
我需要对 'react-select' (github repo) 进行简单的 "required" 验证。
在最新版本中,它使用 css-in-js 方法。所以我有自定义样式:
export const customStyles = {
control: (base, state) => ({
...base,
}),
menu: (base, state) => ({
...base,
}),
menuList: (base, state) => ({
...base,
}),
}
我该如何更改,例如borderColor
如果字段无效?
关于这一点,GitHub 上有一个问题。
我看到两种不同的方法:
- "lazy" 一个,您可以通过添加特定
className
来更改边框颜色。 Example here.
- 因为你想自定义原始 select 我建议将你的
customSelect
嵌入到一个单独的文件中。然后你可以传递一个道具 isValid
并用它来改变你的 borderColor
.
class CustomSelect extends React.Component {
render() {
const {
isValid
} = this.props
const customStyles = {
control: (base, state) => ({
...base,
// state.isFocused can display different borderColor if you need it
borderColor: state.isFocused ?
'#ddd' : isValid ?
'#ddd' : 'red',
// overwrittes hover style
'&:hover': {
borderColor: state.isFocused ?
'#ddd' : isValid ?
'#ddd' : 'red'
}
})
}
return <Select styles={ customStyles } {...this.props}/>
}
}
render.js
export const renderSelect = (props) => (
<div>
<Select
{...props}
value={props.input.value}
onChange={(value) => props.input.onChange(value)}
onBlur={() => props.input.onBlur(props.input.value)}
options={props.options}
key={props.input.value}
/>
{props.meta.touched && (props.meta.error && <p style={{ color: "red",fontSize:"12px" }}>{props.meta.error}</p>)}
</div>
);
implementForm.js
<Field
name="sex"
component={renderSelect}
options={Status}
isClearable={true}
validate={required}
/>
requiredFileMessage.js
const required = value => value ? undefined : 'Required'
对于那些不想一直为 react-select
中的此必需验证添加一些代码的人的帮助。只需使用 react-hook-form-input
.
<RHFInput
as={<Select options={options} />}
rules={{ required: 'Please select an option'}}
name="reactSelect"
register={register}
setValue={setValue}
/>
react-hook-form-input
中的这个 RHFInput
对我来说只是一个保存.. 完整的例子 - react-hook-form-input
.
import React from 'react';
import useForm from 'react-hook-form';
import { RHFInput } from 'react-hook-form-input';
import Select from 'react-select';
const options = [
{ value: 'chocolate', label: 'Chocolate' },
{ value: 'strawberry', label: 'Strawberry' },
];
function App() {
const { handleSubmit, register, setValue, reset, errors } = useForm();
return (
<form onSubmit={handleSubmit(data => console.log(data))}>
<RHFInput
as={<Select options={options} />}
rules={{ required: 'Please select an option'}}
name="reactSelect"
register={register}
setValue={setValue}
/>
<span className="text-danger">
{errors.reactSelect && errors.reactSelect.type === 'required' && "Please select"}
</span>
<button type="button">Reset Form</button>
<button>submit</button>
</form>
);
}
希望,它能帮助像我这样的 React 初学者。
我发现的最佳方法是创建一个透明的输入字段,该字段将通过 javascript 标准 checkValidity 进行查询。这应该有绝对定位和 100% 的宽度和高度。然后,您可以将侦听器绑定到由 checkValidity
创建的无效事件的输入字段
这是我使用的代码。值字段的使用以及一些样式(对于 MDB 输入)都有更改,但您只需更改输入的 类 即可匹配您自己的样式库。通过这种方式,您的验证样式将与您现有的表单输入相同。
希望这对某人有所帮助。
/**************************************************************************************
*** Select - New Select Control Using react-select (to stop stupid probs with MDB) ***
**************************************************************************************/
// Use This progressively instead of InputSelect
/* Differences from native ReactSelect
Validation - Applies transparent input overlay that works with form checkValidity()
value: This is the record.field value not an object {label: x, value: y} as for react-select
grouped: Explicitly set grouped options when set true
objValue: Works the same as react-select value object
*/
// Note: value property works differently do react-select , use ObjValue to work same as react-select
export const Select = (props) => {
let { id, options, cols, value, objValue, label, grouped, ...o } = props
id = id ? id : 'react-select'
const [selected, setSelected] = useState(value)
const [invalid, setInvalid] = useState(false)
//DEFAULTS
if (!grouped) grouped = false
//--------------------------
// VALIDATION EVENT HANDLERS
//--------------------------
useEffect(() => {
//ADD EVENT HANDLER FOR FOR VALIDATION
let ele = document.getElementById(`${id}_invalid}`)
ele.addEventListener('invalid', (e) => {
console.log('e is ', selected, e)
if (typeof selected === 'undefined' || selected !== null) setInvalid(true)
})
//ON COMPONENT EXIT - REMOVE EVENT HANDLER
return () => {
ele.removeEventListener('invalid', () => {
setInvalid(false)
})
}
// eslint-disable-next-line
}, [])
//Value property (Allows Single field assignent) - translates to object in for {label:x, value:y}
useEffect(() => {
let val
if (grouped) {
val = _.findInGroup(options, 'options', (rec) => rec.value === value)
} else {
val = options.find((rec) => rec.value === value)
}
//console.log('Selected==>', val)
setSelected(val)
// eslint-disable-next-line
}, [value, options])
//objValue Property (Emulate standard react-select value object)
useEffect(() => {
if (objValue) {
setSelected(objValue)
}
// eslint-disable-next-line
}, [objValue])
//STYLING SAME AS MDB INPUT COMPONENTS
const customStyles = {
valueContainer: (provided, state) => ({
...provided,
backgroundColor: 'aliceblue',
}),
dropdownIndicator: (provided, state) => ({
...provided,
backgroundColor: 'aliceblue',
}),
}
const handleChange = (opt, i) => {
setSelected(opt)
//Callback function (i is used for nested data in record)
if (props && props.onChange) props.onChange(opt, i)
}
return (
<Col cols={cols}>
{label && <label className='tp-label text-uppercase'>{label}</label>}
<div className='select-wrapper'>
<ReactSelect
styles={customStyles}
value={selected ? selected : ''}
options={options}
onChange={(val, i) => handleChange(val, i)}
isSearchable={true}
{...o}
/>
<input
id={`${id}_invalid}`}
name={`${id}_invalid}`}
value={selected ? selected : ''}
onChange={() => {}}
tabIndex={-1}
className={`form-control tp-input w-100 ${invalid ? '' : 'd-none'}`}
autoComplete='off'
//value={selected}
onFocus={() => {
setInvalid(false)
}}
style={{
position: 'absolute',
color: 'transparent',
backgroundColor: 'transparent',
top: 0,
left: 0,
width: '100%',
height: '100%',
zIndex: 0,
}}
required={true}
/>
</div>
</Col>
)
}
看看这个link:https://codesandbox.io/s/react-hook-form-controller-079xx?file=/src/index.js
你必须使用控制器
<Controller
control={control}
rules={{ required: true }}
name="citySelect"
getOptionLabel={(option) => option.name}
getOptionValue={(option) => option.id}
options={citiesOption}
value={city}
onChange={handleCity}
className="basic-single"
classNamePrefix="select"
isRtl
placeholder="استان مورد نظر"
as={Select}
/>
{errors.citySelect && <p>choose a city</p>}
React-Select style for Bootstrap 5 validation
class CustomSelect extends React.Component {
render() {
const { valid, invalid } = this.props;
let borderColor = '#ced4da';
let focusBorderColor = '#66afe9';
let focusBoxShadow = '0 0 0 .2rem rgba(0, 123, 255, 0.25)';
if (valid) {
borderColor = '#198754';
focusBorderColor = '#198754';
focusBoxShadow = '0 0 0 .2rem rgba(25, 135, 84, .25)';
} else if (invalid) {
borderColor = '#dc3545';
focusBorderColor = '#dc3545';
focusBoxShadow = '0 0 0 .2rem rgba(220, 53, 69, .25)';
}
const customStyles = {
valueContainer: (provided, state) => ({
...provided,
borderColor: state.selectProps.menuIsOpen ? focusBorderColor : borderColor,
boxShadow: state.selectProps.menuIsOpen ? focusBoxShadow : 'none',
}),
};
return (
<Select styles={customStyles} {...this.props} />
);
}
}
我需要对 'react-select' (github repo) 进行简单的 "required" 验证。 在最新版本中,它使用 css-in-js 方法。所以我有自定义样式:
export const customStyles = {
control: (base, state) => ({
...base,
}),
menu: (base, state) => ({
...base,
}),
menuList: (base, state) => ({
...base,
}),
}
我该如何更改,例如borderColor
如果字段无效?
关于这一点,GitHub 上有一个问题。
我看到两种不同的方法:
- "lazy" 一个,您可以通过添加特定
className
来更改边框颜色。 Example here. - 因为你想自定义原始 select 我建议将你的
customSelect
嵌入到一个单独的文件中。然后你可以传递一个道具isValid
并用它来改变你的borderColor
.
class CustomSelect extends React.Component {
render() {
const {
isValid
} = this.props
const customStyles = {
control: (base, state) => ({
...base,
// state.isFocused can display different borderColor if you need it
borderColor: state.isFocused ?
'#ddd' : isValid ?
'#ddd' : 'red',
// overwrittes hover style
'&:hover': {
borderColor: state.isFocused ?
'#ddd' : isValid ?
'#ddd' : 'red'
}
})
}
return <Select styles={ customStyles } {...this.props}/>
}
}
render.js
export const renderSelect = (props) => (
<div>
<Select
{...props}
value={props.input.value}
onChange={(value) => props.input.onChange(value)}
onBlur={() => props.input.onBlur(props.input.value)}
options={props.options}
key={props.input.value}
/>
{props.meta.touched && (props.meta.error && <p style={{ color: "red",fontSize:"12px" }}>{props.meta.error}</p>)}
</div>
);
implementForm.js
<Field
name="sex"
component={renderSelect}
options={Status}
isClearable={true}
validate={required}
/>
requiredFileMessage.js
const required = value => value ? undefined : 'Required'
对于那些不想一直为 react-select
中的此必需验证添加一些代码的人的帮助。只需使用 react-hook-form-input
.
<RHFInput
as={<Select options={options} />}
rules={{ required: 'Please select an option'}}
name="reactSelect"
register={register}
setValue={setValue}
/>
react-hook-form-input
中的这个 RHFInput
对我来说只是一个保存.. 完整的例子 - react-hook-form-input
.
import React from 'react';
import useForm from 'react-hook-form';
import { RHFInput } from 'react-hook-form-input';
import Select from 'react-select';
const options = [
{ value: 'chocolate', label: 'Chocolate' },
{ value: 'strawberry', label: 'Strawberry' },
];
function App() {
const { handleSubmit, register, setValue, reset, errors } = useForm();
return (
<form onSubmit={handleSubmit(data => console.log(data))}>
<RHFInput
as={<Select options={options} />}
rules={{ required: 'Please select an option'}}
name="reactSelect"
register={register}
setValue={setValue}
/>
<span className="text-danger">
{errors.reactSelect && errors.reactSelect.type === 'required' && "Please select"}
</span>
<button type="button">Reset Form</button>
<button>submit</button>
</form>
);
}
希望,它能帮助像我这样的 React 初学者。
我发现的最佳方法是创建一个透明的输入字段,该字段将通过 javascript 标准 checkValidity 进行查询。这应该有绝对定位和 100% 的宽度和高度。然后,您可以将侦听器绑定到由 checkValidity
创建的无效事件的输入字段这是我使用的代码。值字段的使用以及一些样式(对于 MDB 输入)都有更改,但您只需更改输入的 类 即可匹配您自己的样式库。通过这种方式,您的验证样式将与您现有的表单输入相同。
希望这对某人有所帮助。
/**************************************************************************************
*** Select - New Select Control Using react-select (to stop stupid probs with MDB) ***
**************************************************************************************/
// Use This progressively instead of InputSelect
/* Differences from native ReactSelect
Validation - Applies transparent input overlay that works with form checkValidity()
value: This is the record.field value not an object {label: x, value: y} as for react-select
grouped: Explicitly set grouped options when set true
objValue: Works the same as react-select value object
*/
// Note: value property works differently do react-select , use ObjValue to work same as react-select
export const Select = (props) => {
let { id, options, cols, value, objValue, label, grouped, ...o } = props
id = id ? id : 'react-select'
const [selected, setSelected] = useState(value)
const [invalid, setInvalid] = useState(false)
//DEFAULTS
if (!grouped) grouped = false
//--------------------------
// VALIDATION EVENT HANDLERS
//--------------------------
useEffect(() => {
//ADD EVENT HANDLER FOR FOR VALIDATION
let ele = document.getElementById(`${id}_invalid}`)
ele.addEventListener('invalid', (e) => {
console.log('e is ', selected, e)
if (typeof selected === 'undefined' || selected !== null) setInvalid(true)
})
//ON COMPONENT EXIT - REMOVE EVENT HANDLER
return () => {
ele.removeEventListener('invalid', () => {
setInvalid(false)
})
}
// eslint-disable-next-line
}, [])
//Value property (Allows Single field assignent) - translates to object in for {label:x, value:y}
useEffect(() => {
let val
if (grouped) {
val = _.findInGroup(options, 'options', (rec) => rec.value === value)
} else {
val = options.find((rec) => rec.value === value)
}
//console.log('Selected==>', val)
setSelected(val)
// eslint-disable-next-line
}, [value, options])
//objValue Property (Emulate standard react-select value object)
useEffect(() => {
if (objValue) {
setSelected(objValue)
}
// eslint-disable-next-line
}, [objValue])
//STYLING SAME AS MDB INPUT COMPONENTS
const customStyles = {
valueContainer: (provided, state) => ({
...provided,
backgroundColor: 'aliceblue',
}),
dropdownIndicator: (provided, state) => ({
...provided,
backgroundColor: 'aliceblue',
}),
}
const handleChange = (opt, i) => {
setSelected(opt)
//Callback function (i is used for nested data in record)
if (props && props.onChange) props.onChange(opt, i)
}
return (
<Col cols={cols}>
{label && <label className='tp-label text-uppercase'>{label}</label>}
<div className='select-wrapper'>
<ReactSelect
styles={customStyles}
value={selected ? selected : ''}
options={options}
onChange={(val, i) => handleChange(val, i)}
isSearchable={true}
{...o}
/>
<input
id={`${id}_invalid}`}
name={`${id}_invalid}`}
value={selected ? selected : ''}
onChange={() => {}}
tabIndex={-1}
className={`form-control tp-input w-100 ${invalid ? '' : 'd-none'}`}
autoComplete='off'
//value={selected}
onFocus={() => {
setInvalid(false)
}}
style={{
position: 'absolute',
color: 'transparent',
backgroundColor: 'transparent',
top: 0,
left: 0,
width: '100%',
height: '100%',
zIndex: 0,
}}
required={true}
/>
</div>
</Col>
)
}
看看这个link:https://codesandbox.io/s/react-hook-form-controller-079xx?file=/src/index.js
你必须使用控制器
<Controller
control={control}
rules={{ required: true }}
name="citySelect"
getOptionLabel={(option) => option.name}
getOptionValue={(option) => option.id}
options={citiesOption}
value={city}
onChange={handleCity}
className="basic-single"
classNamePrefix="select"
isRtl
placeholder="استان مورد نظر"
as={Select}
/>
{errors.citySelect && <p>choose a city</p>}
React-Select style for Bootstrap 5 validation
class CustomSelect extends React.Component {
render() {
const { valid, invalid } = this.props;
let borderColor = '#ced4da';
let focusBorderColor = '#66afe9';
let focusBoxShadow = '0 0 0 .2rem rgba(0, 123, 255, 0.25)';
if (valid) {
borderColor = '#198754';
focusBorderColor = '#198754';
focusBoxShadow = '0 0 0 .2rem rgba(25, 135, 84, .25)';
} else if (invalid) {
borderColor = '#dc3545';
focusBorderColor = '#dc3545';
focusBoxShadow = '0 0 0 .2rem rgba(220, 53, 69, .25)';
}
const customStyles = {
valueContainer: (provided, state) => ({
...provided,
borderColor: state.selectProps.menuIsOpen ? focusBorderColor : borderColor,
boxShadow: state.selectProps.menuIsOpen ? focusBoxShadow : 'none',
}),
};
return (
<Select styles={customStyles} {...this.props} />
);
}
}