- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个带有一些文本输入和一些自定义组件的表单。我已经对文本输入进行了 Formik 验证,但对自定义组件没有进行验证。我现在正尝试将 Formik 验证添加到我的自定义 categoriesMultiselect
组件中。该组件将其数据保存在 redux 存储中。我自己处理了验证并为我的 redux Prop 添加了一个值:
const mapStateToProps = (
state: RecordOf<VepoState>,
ownProps: { rerenderKey: boolean }
) => ({...
isCategoriesValid: selectIsCategoriesValid(state),
...
})
.我只想将 props.isCategoriesValid
插入到我的 Formik 表单中。
通过阅读官方文档,我想我是通过将 validate={validateCategories}
作为属性添加到自定义组件并将函数 validateCategories
添加到组件来实现的.所以我试过这样:
//above React render()
validateCategories = () => {
let error
if (!this.props.selectIsCategoriesValid) {
error = 'please select a category'
}
return error
}
// Inside React render()
<CategoriesMultiselect.View
validate={this.validateCategories}
name={'categories'}
label={'Product Categories'}
categoryCodes={[CategoryEnums.CategoryCodes.Grocery]}
/>
validateCategories
永远不会运行。这就是为什么我通过将 validateField
添加到我的输入 onChange
函数之一来测试运行它的原因:
<Input
label={'Product Brand'}
value={values.brand}
onTouch={setFieldTouched}
error={touched.brand && errors.brand}
placeholder="Enter Brand"
name="brand"
required
onChange={() => validateField('categories')}
deleteText={setFieldValue}
/>
当它尝试验证该字段时,我收到控制台错误:
Cannot read property 'validate' of undefined
在 Formik 中的这一行代码中:
var validateField = useEventCallback(function (name) {
if (isFunction(fieldRegistry.current[name].validate)) {
我至少已将 Formik 插入到我的 Redux 中,因为我至少在提交表单时成功地分派(dispatch)了 Redux 操作。我做错了什么?
代码:
//@flow
import * as Yup from 'yup'
import { Formik, withFormik } from 'formik'
import { Container } from 'native-base'
import * as React from 'react'
import { ScrollView, View, Alert, Button } from 'react-native'
import { connect } from 'react-redux'
import { Category as CategoryEnums } from 'src/enums'
import type { VepoState } from 'src/components/model'
import type { RecordOf } from 'immutable'
import type { Product } from 'src/model'
import VepoHeader from 'src/components/formControls/header/view'
import { selectIsAddFormValid } from './selector'
import { selectProduct } from './selector'
// import { Button } from 'src/components/formControls'
import { ImagePicker } from 'src/components/formControls'
import LocationAutocomplete from 'src/components/formControls/locationAutocomplete/view'
import { uploadAddProduct, updateRerenderKey } from './action'
import { viewStyle } from './style'
import type { Dispatch } from 'redux'
import { updateAddProductImage } from './action'
import type { Place } from 'src/model/location'
import { Colors, Spacing } from 'src/styles'
import { Input } from 'src/components/formControls'
import { onPress } from './controller'
import { CategoriesMultiselect } from 'src/components/formControls'
import {
selectIsGrocerySelected,
selectIsCategoriesValid,
isLocationValid
} from 'src/components/product/add/groceryItem/selector'
const mapStateToProps = (
state: RecordOf<VepoState>,
ownProps: { rerenderKey: boolean }
) => ({
locationListDisplayed: state.formControls.root.locationListDisplayed,
isAddFormValid: selectIsAddFormValid(state),
// $FlowFixMe
product: selectProduct(state),
// $FlowFixMe
isGrocerySelected: selectIsGrocerySelected(state),
// $FlowFixMe
categories: state.formControls.categories,
isCategoriesValid: selectIsCategoriesValid(state),
image: state.product.add.image,
rerenderKey: ownProps.rerenderKey,
location: state.formControls.location,
isLocationValid: isLocationValid(state)
})
// eslint-disable-next-line flowtype/no-weak-types
const mapDispatchToProps = (dispatch: Dispatch<*>): Object => ({
updateAddProductImage: (value): void => {
dispatch(updateAddProductImage({ value }))
},
uploadAddProduct: (product: Product): void => {
dispatch(uploadAddProduct(product))
},
updateRerenderKey: () => {
dispatch(updateRerenderKey())
}
})
export const getLocationIsValid = (place: Place): boolean => {
return Object.keys(place).length > 0 ? true : false
}
type AddGroceryStoreState = {
name: string,
brand: string,
description: string,
price?: number
}
class AddGroceryItemView extends React.Component<any, AddGroceryStoreState> {
validateCategories = () => {
let error
if (!this.props.selectIsCategoriesValid) {
error = 'please select a category'
}
return error
}
render() {
const {
values,
handleSubmit,
setFieldValue,
errors,
touched,
setFieldTouched,
isValid,
isSubmitting,
validateField
} = this.props
return (
<Container>
<VepoHeader title={'Add Vegan Grocery Product'} />
<Container style={container}>
<ScrollView
keyboardShouldPersistTaps="always"
style={viewStyle(this.props.locationListDisplayed).scrollView}>
<View>
<LocationAutocomplete
label={'Grocery Store'}
placeHolder={'Enter Grocery Store'}
/>
</View>
<View style={viewStyle().detailsContainer}>
<ImagePicker
label={'Product Image (optional)'}
image={this.props.image.image}
updateAddProductImage={this.props.updateAddProductImage}
updateRerenderKey={this.props.updateRerenderKey}
/>
<Input
label={'Product Name'}
onTouch={setFieldTouched}
value={values.name}
placeholder="Enter Name"
name="name"
required
error={touched.name && errors.name}
deleteText={setFieldValue}
onChange={setFieldValue}
/>
<Input
label={'Product Brand'}
value={values.brand}
onTouch={setFieldTouched}
error={touched.brand && errors.brand}
placeholder="Enter Brand"
name="brand"
required
onChange={() => validateField('categories')}
deleteText={setFieldValue}
/>
<View>
<Input
label={'Product Description'}
value={values.description}
placeholder="Enter Description"
multiline={true}
required
onTouch={setFieldTouched}
error={touched.description && errors.description}
numberOfLines={4}
name="description"
deleteText={setFieldValue}
onChange={setFieldValue}
/>
<Input
isValid={true}
isPrice={true}
label={'Product Price'}
value={values.price}
onTouch={setFieldTouched}
error={touched.price && errors.price}
placeholder="Enter Price"
name="price"
deleteText={setFieldValue}
onChange={setFieldValue}
/>
<View>
<CategoriesMultiselect.View
validate={this.validateCategories}
name={'categories'}
label={'Product Categories'}
categoryCodes={[CategoryEnums.CategoryCodes.Grocery]}
/>
</View>
</View>
</View>
</ScrollView>
</Container>
<Button
title="submit"
onPress={handleSubmit}
disabled={!isValid || isSubmitting}
loading={isSubmitting}
/>
{/* <Button.View onSub={this._handleSubmit} onPress={this._handleSubmit} label={'GO!'} /> */}
</Container>
)
}
}
const container = {
flex: 1,
...Spacing.horizontalPaddingLarge,
backgroundColor: Colors.greyLight,
flexDirection: 'column'
}
const formikEnhancer = withFormik({
validationSchema: Yup.object().shape({
name: Yup.string().required(),
brand: Yup.string().required(),
categories: Yup.array(),
description: Yup.string()
.min(9)
.required(),
price: Yup.number()
.typeError('price must be a number')
.required()
}),
mapPropsToValues: () => ({
name: '',
brand: '',
description: '',
price: '',
categories: []
}),
handleSubmit: (values, { props }) => {
props.updateRerenderKey()
},
displayName: 'AddGroceryItemView'
})(AddGroceryItemView)
// $FlowFixMe
const AddGroceryItemViewComponent = connect(
mapStateToProps,
mapDispatchToProps
)(formikEnhancer)
export default AddGroceryItemViewComponent
根据 Rikin 的要求,这是 CategoriesMultiselect 组件:
//@flow
import type { Node } from 'react'
import { selectSelectedCategory } from 'src/components/product/add/groceryItem/selector'
import type { VepoState } from 'src/components/model'
import type { RecordOf } from 'immutable'
import { connect } from 'react-redux'
import * as React from 'react'
import { View } from 'react-native'
import {
List,
ListItem,
Text,
Left,
Body,
Right,
Button,
Container,
Label,
Title,
Content
} from 'native-base'
import Icon from 'react-native-vector-icons/FontAwesome'
import Eicon from 'react-native-vector-icons/EvilIcons'
import Modal from 'react-native-modal'
import SelectMultiple from 'react-native-select-multiple'
import {
updateAlertModalIsOpen,
updateAlertModalHasYesNo,
updateAlertModalMessage,
updateAlertModalTitle
} from 'src/components/formControls/alertModal/action'
import * as C from './model'
import type { Subcategory } from 'src/model/category'
import * as controller from './controller'
import { getIsCategoriesValid } from './controller'
import { styles } from 'src/components/style'
import {
Colors,
Corners,
Distances,
Modals,
Spacing,
Typography,
ZIndexes
} from 'src/styles'
import { Containers } from '../../../styles'
import {
toggleSubcategory,
setAllShowSubcategoriesToFalse,
toggleShowSubcategories
} from './action'
import type { Dispatch } from 'redux'
const mapStateToProps = (state: RecordOf<VepoState>) => ({
vepo: state,
// $FlowFixMe
selectedCategory: selectSelectedCategory(state),
categories: state.formControls.categories
})
// eslint-disable-next-line flowtype/no-weak-types
const mapDispatchToProps = (dispatch: Dispatch<*>): Object => ({
setAllShowSubcategoriesToFalse: (): void => {
dispatch(setAllShowSubcategoriesToFalse())
},
toggleSubcategory: (sc): void => {
return dispatch(toggleSubcategory(sc))
},
toggleShowSubcategories: (c): void => {
dispatch(toggleShowSubcategories(c))
},
updateAlertModalIsOpen: (isOpen: boolean): void => {
dispatch(updateAlertModalIsOpen(isOpen))
},
updateAlertModalMessage: (message: string): void => {
dispatch(updateAlertModalMessage(message))
},
updateAlertModalHasYesNo: (hasYesNo: boolean): void => {
dispatch(updateAlertModalHasYesNo(hasYesNo))
},
updateAlertModalTitle: (title: string): void => {
dispatch(updateAlertModalTitle(title))
}
})
const renderCategoryRow = (props: C.CategoriesViewProps, item: C.Category) => {
return (
<View>
<ListItem
style={listItem}
icon
onPress={() => controller.categoryClicked(props, item)}>
<Left>
<Icon
style={styles.icon}
name={item.icon}
size={20}
color={item.iconColor}
/>
</Left>
<Body style={[styles.formElementHeight, border(item)]}>
<Text style={Typography.brownLabel}>{item.label}</Text>
</Body>
<Right style={[styles.formElementHeight, border(item)]}>
<Eicon style={catStyle.arrow} name="chevron-right" size={30} />
</Right>
</ListItem>
</View>
)
}
const getCategoriesToDisplay = (props) => {
const y = props.categories.filter((x) => props.categoryCodes.includes(x.code))
return y
}
class CategoriesMultiselectView extends React.Component {
setFormCategories = () => {
if (this.props && this.props.setFieldValue) {
this.props.setFieldValue(
'categories',
controller.getSelectedSubcategories(this.props.categories)
)
}
}
render(): React.Node {
const categoriesToDisplay = getCategoriesToDisplay(this.props)
return (
<View>
<View style={{ ...Containers.fullWidthRow }}>
<Label disabled={false} style={Typography.formLabel}>
{this.props.label}
</Label>
<View style={{ ...Containers.fullWidthRow }} />
<Label disabled={false} style={Typography.formLabel}>
{controller.getNumberOfSelectedSubcategories(this.props.categories)}{' '}
Selected
</Label>
</View>
<View
style={catStyle.categoriesViewStyle(this.props, categoriesToDisplay)}>
{this.props.categories && this.props.categories.length > 0 && (
<List
listBorderColor={'white'}
style={categoriesListStyle}
dataArray={categoriesToDisplay}
renderRow={(item: C.Category) => {
return renderCategoryRow(this.props, item)
}}
/>
)}
<View style={catStyle.modalConatinerStyle} />
<Modal
style={catStyle.modal}
onModalHide={this.setFormCategories}
isVisible={
this.props.categories
? this.props.categories.some((cat: C.Category) =>
controller.showModal(cat)
)
: false
}>
<Container style={catStyle.modalView}>
<View style={Modals.modalHeader}>
<Title style={catStyle.categoriesTitleStyle}>
{controller.getDisplayedCategoryLabel(this.props.categories)}
</Title>
<Right>
<Button
transparent
icon
onPress={this.props.setAllShowSubcategoriesToFalse}>
<Eicon name="close-o" size={25} color="#FFFFFF" />
</Button>
</Right>
</View>
<Content style={catStyle.categoryStyle.modalContent}>
<SelectMultiple
checkboxSource={require('../../../images/unchecked.png')}
selectedCheckboxSource={require('../../../images/checked.png')}
labelStyle={[
styles.label,
styles.formElementHeight,
styles.modalListItem
]}
items={controller.getDisplayedSubcategories(
this.props.categories
)}
selectedItems={controller.getSelectedSubcategories(
this.props.categories
)}
onSelectionsChange={(selections, item: Subcategory) => {
this.props.toggleSubcategory({ subcategory: item }).the
}}
/>
</Content>
</Container>
</Modal>
</View>
{this.props.error && (
<Label
disabled={false}
style={[
Typography.formLabel,
{ color: 'red' },
{ marginBottom: Spacing.medium }
]}>
{this.props.error}
</Label>
)}
</View>
)
}
}
const catStyle = {
// eslint-disable-next-line no-undef
getBorderBottomWidth: (item: C.Category): number => {
if (item.icon === 'shopping-basket') {
return Spacing.none
}
return Spacing.none
},
// eslint-disable-next-line no-undef
categoriesViewStyle: (props: C.CategoriesViewProps, categoriesToDisplay) => {
return {
backgroundColor: Colors.borderLeftColor(
getIsCategoriesValid(props.categories)
),
...Corners.rounded,
paddingLeft: Spacing.medium,
height: Distances.FormElementHeights.Medium * categoriesToDisplay.length,
overflow: 'hidden',
borderBottomWidth: Spacing.none
}
},
arrow: {
color: Colors.brownDark,
borderBottomColor: Colors.brownDark
},
icon: { height: Distances.FormElementHeights.Medium },
// eslint-disable-next-line no-undef
categoriesTitleStyle: {
...styles.title,
...Typography.titleLeftAlign
},
categoryStyle: {
modalContent: {
...Corners.rounded
}
},
modal: {
flex: 0.7,
height: 20,
marginTop: Spacing.auto,
marginBottom: Spacing.auto
},
modalView: {
backgroundColor: Colors.white,
height: 500,
...Corners.rounded
},
modalConatinerStyle: {
marginBottom: Spacing.medium,
color: Colors.brownDark,
backgroundColor: Colors.brownLight,
position: 'absolute',
zIndex: ZIndexes.Layers.Negative,
right: Spacing.none,
height: Distances.Distances.Full,
width: Distances.Distances.Full,
...Corners.rounded
}
}
const categoriesListStyle = {
flex: Distances.FlexDistances.Full,
color: Colors.brownDark,
backgroundColor: Colors.brownLight,
height: Distances.FormElementHeights.Double,
...Corners.notRounded,
marginRight: Spacing.medium
}
const border = (item: C.Category) => {
return {
borderBottomWidth: catStyle.getBorderBottomWidth(item),
borderBottomColor: Colors.brownMedium
}
}
const listItem = {
height: Distances.FormElementHeights.Medium
}
// $FlowFixMe
const CategoriesMultiselect = connect(
mapStateToProps,
mapDispatchToProps
)(CategoriesMultiselectView)
export default CategoriesMultiselect
最佳答案
通过直接在表单 categories
中设置属性并带有错误消息的表单级别验证用法示例。
...
...
...
const validateCategories = (values, props) => {
let error = {}
if (!props.selectIsCategoriesValid) {
error.categories = 'please select a category'
}
return error
}
class AddGroceryItemView extends React.Component<any, AddGroceryStoreState> {
render() {
const { ... } = this.props
return (
<Container>
<VepoHeader title={'Add Vegan Grocery Product'} />
<Container style={container}>
<ScrollView
keyboardShouldPersistTaps="always"
style={viewStyle(this.props.locationListDisplayed).scrollView}>
<View>
...
</View>
<View style={viewStyle().detailsContainer}>
...
<View>
...
<View>
<CategoriesMultiselect.View
// validate={this.validateCategories}
name={'categories'}
label={'Product Categories'}
categoryCodes={[CategoryEnums.CategoryCodes.Grocery]}
/>
</View>
</View>
</View>
</ScrollView>
</Container>
...
</Container>
)
}
}
...
const formikEnhancer = withFormik({
validationSchema: Yup.object().shape({
...
}),
mapPropsToValues: () => ({
...
}),
handleSubmit: (values, { props }) => {
...
},
displayName: 'AddGroceryItemView',
validate: validateCategories
})(AddGroceryItemView)
// $FlowFixMe
const AddGroceryItemViewComponent = connect(
mapStateToProps,
mapDispatchToProps
)(formikEnhancer)
export default AddGroceryItemViewComponent
使用 Formik 的 Field
更新字段级验证:
但是我个人会选择表单级别验证作为你依赖的第一道防线- 在 validationSchema 通过测试后,您可以在其中放置自定义消息传递的级别。如果您在现场级别进行操作,那么您可能最终会陷入困境,这可能会导致难以维护组件并针对应用程序中的各个场景对其进行自定义。对我来说,表单级验证在一个方便的地方就足够明确了,可以进行所有额外的字段级验证。或者,您也可以将所有 validationSchema
和表单级验证函数放在一个文件中,然后将其导入到您要包装 withFormik
HOC 的主要组件中。
无论哪种方式,都取决于您的需求。
这是官方文档链接:https://jaredpalmer.com/formik/docs/guides/validation#field-level-validation
并且按照那个:
Note: The / components' validate function will only be executed on mounted fields. That is to say, if any of your fields unmount during the flow of your form (e.g. Material-UI's unmounts the previous your user was on), those fields will not be validated during form validation/submission.
//@flow
...
import SelectMultiple from 'react-native-select-multiple'
...
import {
toggleSubcategory,
setAllShowSubcategoriesToFalse,
toggleShowSubcategories
} from './action'
...
import { Field } from 'formik'
...
class CategoriesMultiselectView extends React.Component {
setFormCategories = () => {
if (this.props && this.props.setFieldValue) {
this.props.setFieldValue(
'categories',
controller.getSelectedSubcategories(this.props.categories)
)
}
}
render(): React.Node {
const categoriesToDisplay = getCategoriesToDisplay(this.props)
return (
<View>
<View style={{ ...Containers.fullWidthRow }}>
...
</View>
<View
style={catStyle.categoriesViewStyle(this.props, categoriesToDisplay)}>
{...}
<View style={catStyle.modalConatinerStyle} />
<Modal
style={catStyle.modal}
onModalHide={this.setFormCategories}
isVisible={
this.props.categories
? this.props.categories.some((cat: C.Category) =>
controller.showModal(cat)
)
: false
}>
<Container style={catStyle.modalView}>
<View style={Modals.modalHeader}>
...
</View>
<Content style={catStyle.categoryStyle.modalContent}>
<Field name="categories" validate={validate_Function_HERE_which_can_be_via_props_or_locally_defined} render={({field, form}) =>
<SelectMultiple
checkboxSource={require('../../../images/unchecked.png')}
selectedCheckboxSource={require('../../../images/checked.png')}
labelStyle={[
styles.label,
styles.formElementHeight,
styles.modalListItem
]}
items={controller.getDisplayedSubcategories(
this.props.categories
)}
selectedItems={controller.getSelectedSubcategories(
this.props.categories
)}
onSelectionsChange={(selections, item: Subcategory) => {
this.props.toggleSubcategory({ subcategory: item }).the
}}
/>}
/>
</Content>
</Container>
</Modal>
</View>
{this.props.error && (
<Label
disabled={false}
style={[
Typography.formLabel,
{ color: 'red' },
{ marginBottom: Spacing.medium }
]}>
{this.props.error}
</Label>
)}
</View>
)
}
}
...
// $FlowFixMe
const CategoriesMultiselect = connect(
mapStateToProps,
mapDispatchToProps
)(CategoriesMultiselectView)
export default CategoriesMultiselect
关于javascript - Formik - 将自定义组件的自定义验证插入我当前工作的 Formik 表单,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57733920/
在 JSF2 应用程序中遇到验证属性的问题时,有两种主要方法。 使用 Annotation 在 ManagedBean 上定义验证 @ManagedBean public class MyBean {
我想实现一个不常见的功能,我认为 jquery 验证插件将是最好的方法(如果您在没有插件的情况下建议和回答,我们也会欢迎)。我想在用户在输入字段中输入正确的单词后立即隐藏表单。我试过这个: $("
我有几个下拉菜单(类名为month_dropdown),并且下拉菜单的数量不是恒定的。我怎样才能为它们实现 NotEqual 验证。我正在使用 jQuery 验证插件。 这就是我写的 - jQuery
我设法制作了这个网址验证代码并且它起作用了。但我面临着一个问题。我认为 stackoverflow 是获得解决方案的最佳场所。 function url_followers(){ var url=do
我目前正在使用后端服务,该服务允许用户在客户端应用程序上使用 Google Games 库登录。 用户可以通过他们的 gplay ID 向我们发送信息,以便登录或恢复旧帐户。用户向我们发送以下内容,包
我正在尝试验证输入以查看它是否是有效的 IP 地址(可能是部分地址)。 可接受的输入:172、172.112、172.112.113、172.112.113.114 Not Acceptable 输入
我从 Mongoose 验证中得到这条消息: 'Validator failed for path phone with value ``' 这不应该发生,因为不需要电话。 这是我的模型架构: var
我一直在尝试使用Python-LDAP (版本 2.4.19)在 MacOS X 10.9.5 和 Python 2.7.9 下 我想在调用 .start_tls_s() 后验证与给定 LDAP 服务
我正在处理一个仅与 IE6 兼容的旧 javascript 项目(抱歉...),我想仅在 VS 2017 中禁用此项目的 ESLint/CSLint/Javascript 验证/CSS 验证。 我知道
我正在寻找一种方法来验证 Spring 命令 bean 中的 java.lang.Double 字段的最大值和最小值(一个值必须位于给定的值范围之间),例如, public final class W
我正在尝试在 springfuse(JavaEE 6 + Spring Framework (针对 Jetty、Tomcat、JBoss 等)) 和 maven 的帮助下构建我的 webapps 工作
我试图在我们的项目中使用 scalaz 验证,但遇到了以下情况: def rate(username: String, params: Map[String, String]): Validation
我有一个像这样的 Yaml 文件 name: hhh_aaa_bbb arguments: - !argument name: inputsss des
我有一个表单,人们可以单击并向表单添加字段,并且我需要让它在单击时验证这些字段中的值。 假设我单击它两次并获取 2 个独立的字段集,我需要旋转 % 以确保它在保存时等于 100。 我已放入此函数以使其
在我的页面中有一个选项可以创建新的日期字段输入框。用户可以根据需要创建尽可能多的“截止日期”和“起始日期”框。就像, 日期_to1 || date_from1 日期到2 ||日期_from2 date
我有一个像这样的 Yaml 文件 name: hhh_aaa_bbb arguments: - !argument name: inputsss des
有没有办法在动态字段上使用 jquery 验证表单。 我想将其设置为必填字段 我正在使用 Jsp 动态创建表单字段。 喜欢 等等...... 我想使用必需的表单字段验证此表单字段。 最佳答
嗨,任何人都可以通过提供 JavaScript 代码来帮助我验证用户名文本框不应包含数字,它只能包含一个字符。 最佳答案 使用正则表达式: (\d)+ 如果找到匹配项,则字符串中就有一个数字。 关于J
我有两个输入字段holidayDate和Description(id=tags) $(document).ready(function() {
我遇到了这个问题,这些验证从电子邮件验证部分开始就停止工作。 我只是不明白为什么即使经过几天的观察,只是想知道是否有人可以在这里指出我的错误? Javascript部分: function valid
我是一名优秀的程序员,十分优秀!