Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/entity-framework/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript Formik-将自定义组件的自定义验证插入到我当前工作的Formik表单中_Javascript_Reactjs_React Native_Formik_Yup - Fatal编程技术网

Javascript Formik-将自定义组件的自定义验证插入到我当前工作的Formik表单中

Javascript Formik-将自定义组件的自定义验证插入到我当前工作的Formik表单中,javascript,reactjs,react-native,formik,yup,Javascript,Reactjs,React Native,Formik,Yup,我有一个表单,有一些文本输入和一些自定义组件。我对文本输入进行了Formik验证,但没有自定义组件。我现在正试图将Formik验证添加到我的自定义categoriesMultiselect组件中。此组件将其数据保存在redux存储中。我自己处理了验证,并为我的redux道具增加了价值: const mapStateToProps = ( state: RecordOf<VepoState>, ownProps: { rerenderKey: boolean } ) =>

我有一个表单,有一些文本输入和一些自定义组件。我对文本输入进行了Formik验证,但没有自定义组件。我现在正试图将Formik验证添加到我的自定义
categoriesMultiselect
组件中。此组件将其数据保存在redux存储中。我自己处理了验证,并为我的redux道具增加了价值:

const mapStateToProps = (
  state: RecordOf<VepoState>,
  ownProps: { rerenderKey: boolean }
) => ({...
    isCategoriesValid: selectIsCategoriesValid(state),
...
})
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}
      />
我至少已经将Formik插入到我的Redux中,因为我在提交表单时至少成功地发送了Redux操作。我做错了什么

代码:

/@flow
从“Yup”导入*为Yup
从'Formik'导入{Formik,withFormik}
从“本机基”导入{Container}
从“React”导入*作为React
从“react native”导入{ScrollView、View、Alert、Button}
从“react redux”导入{connect}
从'src/enums'导入{Category as CategoryEnums}
从'src/components/model'导入类型{VepoState}
从“不可变”导入类型{RecordOf}
从'src/model'导入类型{Product}
从“src/components/formControls/header/view”导入VepoHeader
从“/selector”导入{selectIsAddFormValid}
从“./selector”导入{selectProduct}
//从'src/components/formControls'导入{Button}
从'src/components/formControls'导入{ImagePicker}
从“src/components/formControls/LocationAutocomplete/view”导入LocationAutocomplete
从“/action”导入{uploadAddProduct,UpdateRenderKey}
从“./style”导入{viewStyle}
从“redux”导入类型{Dispatch}
从“./action”导入{UpdatedProductImage}
从'src/model/location'导入类型{Place}
从'src/styles'导入{颜色,间距}
从'src/components/formControls'导入{Input}
从“./controller”导入{onPress}
从'src/components/formControls'导入{CategoriesMultiselect}
进口{
选择IsGrocery已选择,
选择分类有效,
isLocationValid
}来自“src/components/product/add/groceryItem/selector”
常量MapStateTops=(
国家:记录,
ownProps:{rerenderKey:boolean}
) => ({
locationListDisplayed:state.formControls.root.locationListDisplayed,
isAddFormValid:选择isAddFormValid(状态),
//$FlowFixMe
产品:选择产品(状态),
//$FlowFixMe
isGrocerySelected:选择isGrocerySelected(状态),
//$FlowFixMe
类别:state.formControls.categories,
isCategoriesValid:选择isCategoriesValid(状态),
image:state.product.add.image,
rerenderKey:ownProps.rerenderKey,
位置:state.formControls.location,
isLocationValid:isLocationValid(状态)
})
//eslint禁用下一行流类型/无弱类型
const mapDispatchToProps=(调度:调度):对象=>({
UpdatedProductImage:(值):void=>{
分派(UpdatedProductImage({value}))
},
uploadAddProduct:(产品:产品):void=>{
发送(上传添加产品(产品))
},
UpdateRenderKey:()=>{
分派(updateRenderKey())
}
})
export const getLocationIsValid=(地点:地点):布尔=>{
返回对象。键(位置)。长度>0?真:假
}
类型AddGroceryStorate={
名称:string,
品牌:string,
描述:字符串,
价格:多少
}
类AddGroceryItemView扩展了React.Component{
validateCategories=()=>{
让错误
如果(!this.props.selectIsCategoriesValid){
错误='请选择一个类别'
}
返回错误
}
render(){
常数{
价值观
手推,
setFieldValue,
错误,
感动的,
塞特菲尔德被感动了,
是有效的,
提交,
验证场
}=这是道具
返回(
validateField('categories')}
deleteText={setFieldValue}
/>
{/*  */}
)
}
}
常量容器={
弹性:1,
…间距。水平填充大,
背景颜色:Colors.greyLight,
flexDirection:“列”
}
常数formikEnhancer=带formik({
validationSchema:Yup.object().shape({
名称:Yup.string().required(),
品牌:Yup.string().required(),
类别:Yup.array(),
description:Yup.string()
.min(9)
.required(),
价格:是的,编号()
.typeError('价格必须是数字')
.required()
}),
mapPropsToValues:()=>({
名称:“”,
品牌:'',
说明:“”,
价格:'',
类别:[]
}),
handleSubmit:(值,{props})=>{
props.updaterenderkey()文件
},
显示名称:“AddGroceryItemView”
})(AddGroceryItemView)
//$FlowFixMe
const AddGroceryItemViewComponent=连接(
MapStateTops,
mapDispatchToProps
)(formikEnhancer)
导出默认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
/@flow
从“react”导入类型{Node}
从'src/components/product/add/groceryItem/selector'导入{selectedcategory}
从'src/components/model'导入类型{VepoState}
从“不可变”导入类型{RecordOf}
从“react redux”导入{connect}
从“React”导入*作为React
从“react native”导入{View}
进口{
列表
列表项,
文本,
左边
身体,
正确的,
按钮
集装箱,
标签,
标题
内容
}来自“本地基地”
从“react native vector icons/Fontsome”导入图标
从“反应本机矢量图标/图标”导入Eicon
从“反应本机模态”导入模态
从“反应本机选择多个”导入SelectMultiple
进口{
updateAlertModalIsOpen,
更新ErtModalHasYesNo,
更新ErtModalMessage,
upd
  var validateField = useEventCallback(function (name) {
if (isFunction(fieldRegistry.current[name].validate)) {
//@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
//@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
...
...
...

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