如何解决Formik,Material UI Autocomplete和Firestore-查询以查找数组参数
您如何修改formik onChange处理程序,以使其仅保存传递给Material UI自动完成字段的选项的值(而不是值加标签的数组)?
我有一个集合,该集合包含一个带有名为category的属性的文档。当前,该类别同时使用表单输入选项中的标签和值填充。
我正在努力寻找一种获取firebase的方法,以便在其中查询以找到数组的value属性。
我想知道如果我尝试仅将值而不是将标签和值保存到Firestore中,是否会更接近可行的解决方案。
import React,{ useState } from "react";
import ReactDOM from "react-dom";
import {render} from 'react-dom';
import { Link } from 'react-router-dom';
import firebase,{firestore} from '../../../firebase';
import { withStyles } from '@material-ui/core/styles';
import {
Button,LinearProgress,MenuItem,FormControl,Divider,InputLabel,FormControlLabel,TextField,Typography,Box,Grid,Dialog,DialogActions,DialogContent,DialogContentText,DialogTitle,} from '@material-ui/core';
import MuiTextField from '@material-ui/core/TextField';
import {
Formik,Form,Field,ErrorMessage,FieldArray,} from 'formik';
import * as Yup from 'yup';
import {
Autocomplete,ToggleButtonGroup,AutocompleteRenderInputParams,} from 'formik-material-ui-lab';
import {
fieldToTextField,TextFieldProps,Select,Switch,CheckBoxWithLabel,CheckBox
} from 'formik-material-ui';
const allCategories = [
{value: 'health',label: 'Health & Medical'},{value: 'general',label: 'General'},];
function UpperCasingTextField(props: TextFieldProps) {
const {
form: {setFieldValue},field: {name},} = props;
const onChange = React.useCallback(
event => {
const {value} = event.target;
setFieldValue(name,value ? value.toupperCase() : '');
},[setFieldValue,name]
);
return <MuiTextField {...fieldToTextField(props)} onChange={onChange} />;
}
function Summary(props) {
const { classes } = props;
const [open,setopen] = useState(false);
const [isSubmitionCompleted,setSubmitionCompleted] = useState(false);
function handleClose() {
setopen(false);
}
function handleClickopen() {
setSubmitionCompleted(false);
setopen(true);
}
return (
<React.Fragment>
<Button
// component="button"
color="primary"
onClick={handleClickOpen}
style={{ float: "right"}}
variant="outlined"
>
Create
</Button>
<Dialog
open={open}
onClose={handleClose}
aria-labelledby="form-dialog-title"
>
{!isSubmitionCompleted &&
<React.Fragment>
<DialogContent>
<Formik
initialValues={{ title: "",category: [],subcategory: "" }}
onSubmit={(values,{ setSubmitting }) => {
setSubmitting(true);
firestore.collection("study").doc().set({
...values,createdAt: firebase.firestore.FieldValue.serverTimestamp()
})
.then(() => {
setSubmitionCompleted(true);
});
}}
validationSchema={Yup.object().shape({
title: Yup.string()
.required('required'),category: Yup.string()
.required('required'),})}
>
{(props) => {
const {
values,touched,errors,dirty,isSubmitting,handleChange,handleBlur,handleSubmit,handleReset,} = props;
return (
<form onSubmit={handleSubmit}>
<TextField
label="Title"
name="title"
// className={classes.textField}
value={values.title}
onChange={handleChange}
onBlur={handleBlur}
helperText={(errors.title && touched.title) && errors.title}
margin="normal"
style={{ width: "100%"}}
/>
<Box margin={1}>
<Field
name="category"
multiple
component={Autocomplete}
options={allCategories}
// value={values.label}
// value={values.value}
// value={allCategories.value}
// value={values.category.allCategories.value}
我尝试了这些尝试中的每一次(一次) 仅填充一个字段-但它们都不起作用 那。相反,firebase会在其数组中记录标签和值。
getoptionLabel={(option: any) => option.label}
style={{width: '100%'}}
renderInput={(params: AutocompleteRenderInputParams) => (
<MuiTextField
{...params}
error={touched['autocomplete'] && !!errors['autocomplete']}
helperText={touched['autocomplete'] && errors['autocomplete']}
label="Category"
variant="outlined"
/>
)}
/>
</Box>
<TextField
label="Subcategory "
name="subcategory"
// className={classes.textField}
value={values.subcategory}
onChange={handleChange}
onBlur={handleBlur}
helperText={(errors.subcategory && touched.subcategory) && errors.subcategory}
margin="normal"
style={{ width: "100%"}}
/>
<DialogActions>
<Button
type="button"
className="outline"
onClick={handleReset}
disabled={!dirty || isSubmitting}
>
Reset
</Button>
<Button type="submit" disabled={isSubmitting}>
Submit
</Button>
{/* <displayFormikState {...props} /> */}
</DialogActions>
</form>
);
}}
</Formik>
</DialogContent>
</React.Fragment>
}
{isSubmitionCompleted &&
<React.Fragment>
<DialogTitle id="form-dialog-title">Done!</DialogTitle>
<DialogContent>
<DialogActions>
<Button
type="button"
className="outline"
onClick={handleClose}
>
Close
</Button>
{/* <displayFormikState {...props} /> */}
</DialogActions>
</DialogContent>
</React.Fragment>}
</Dialog>
</React.Fragment>
);
}
export default Summary;
然后,当我尝试查询Firebase时,我正在尝试查找类别包括健康状况的文档。
我已经尝试了下面的每个where查询,但我无法让它们返回查询的结果(如果删除了where查询,则可以返回所有结果):
function useHealthTerms() {
const [healthTerms,setHealthTerms] = useState([])
useEffect(() => {
firebase
.firestore()
.collection("study")
//.where("title","==","ss")
//.where('category','==','health')
//.where('category.value',"array-contains",'health")
//.where('category','array-contains','health')
//.where('category',1)
//.where("category.1.value",'health')
.onSnapshot(snapshot => {
const healthTerms = snapshot.docs.map(doc => ({
id: doc.id,...doc.data(),}))
setHealthTerms(healthTerms)
})
},[])
return healthTerms
}
我见过this post,但是我不够聪明,无法从答案中获得任何意义。
我也看到了this post和贝蒂建议的答案。我对以下查询构造尝试了多种变体,以尝试使用该想法,但是每次,查询形式都会出错。
.where(new firebase.firestore().Fieldpath("category","value"),'health')
我想知道是否可以尝试在formik中获取类别表单字段,只是为了保存option.value而不是标签和值。
我看不到formik handleChange如何工作以要求它仅保存值。
即使那样,我也看不到如何查询firestore来将数组的内容用作查询参数。
有人知道吗?
这很奇怪,因为this post建议使用上面我尝试过的形式对数组进行where查询。但是,这篇文章建议使用以下格式.collection(study / [docId])。where(“ value”,“ ==”,“ health”)。我需要它来搜索集合中的每个文档,所以我不知道如何将这种方法应用于此问题。
下面来自gso_gabriel的答案提出了两个令人困惑的事情。首先,假设我使用了一个子集合。我没有在父文档中添加以下图片以显示类别字段。我可以使用上面显示的格式对标题进行where查询,以提取值。
其次,最令人困惑的是-它说:“因为您无法在数组内搜索对象”。这是什么意思?是否暗示不能对类别字段中的值的内容执行查询?如果是这样,是否有资源提供有关如何查询此数据的指南?
我还看到了this post-的答案表明,使用Firebase无法查询类别内的值。问题是我无法理解建议的替代方法。如果我正确理解了这篇文章,是否有任何教程对原理进行了扩展,以便我可以尝试找到其他查询策略?
对this post的第一个答案还表明,无法查询类别内的值。第二个答案建议在where查询中使用其他格式-如下。
.where("category",{value: "health",label: "Health & Medical"})
所以-这使我回到了自动完成提交处理程序。这是一个多选字段,因此可能选择了多个值。如何在Firebase文档上将它们变成一组单个值。即使只有一个,如何更改提交处理程序,使其仅发送选择选项值,而不是同时发送值和标签?
如果不可能查询数组中的对象-如何更改提交处理程序以仅将选定的选项值添加到firebase中,而不是标签和值中?对this post的第一个答案中建议的解决方法是添加一个仅包含要查询的值的字段(因此:health)。
解决方法
在通过onSubmit
提交到Firebase之前,您可以更改发送数据的形状
onSubmit={(values,{ setSubmitting }) => {
setSubmitting(true);
firestore.collection("study").doc().set({
...values,category: values.category.map(c => c.value),createdAt: firebase.firestore.FieldValue.serverTimestamp()
})
.then(() => {
setSubmitionCompleted(true);
});
}}
,
我将通过逐一回答您的观点来尝试澄清您的疑问。
- 要仅保存
value
,就需要更改将信息发送到Firestore的方式。更改您的values
变量,因为该变量也要维护label
中的值。总而言之,在与Firestore相关时,您需要基本更改代码,在其中使用label
值进行变量。 - 澄清您提到的here帖子-通常,NoSQL数据库是根据查询方式创建的。因此,您将首先根据需要使用这些查询以及对数据库的结构进行正确处理,这样就不会遇到任何问题。确实,由于您无法在
Array
中搜索对象,因此,我认为重组方案是最佳选择。 - 也许可以使用本示例中阐明的子集合here可能会帮助您简化工作。
更改将是最适合您的选择,因此您可以拥有一个完全适合您的查询和需求的方案-这是NoSQL的许多优点之一,可以自由地创建方案。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。