Formik,Material UI自动完成和Firestore-在哪里查询以找到数组参数 [英] Formik, Material UI Autocomplete and Firestore - where query to find the array parameter

查看:108
本文介绍了Formik,Material UI自动完成和Firestore-在哪里查询以找到数组参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

您如何修改formik onChange处理程序,以使其仅保存传递给Material UI自动完成字段的选项的值(而不是值加标签的数组)?

How do you modify the formik onChange handler so that it saves the value only (rather than an array of the value plus label) for options passed to Material UI Autocomplete field?

我有一个集合,该集合包含一个带有名为category的属性的文档.目前,该类别同时使用表单输入选项中的标签和值填充.

I have a collection which has a document with an attribute called category. Currently, the category gets populated with both the label and value from the form entry options.

我正在努力寻找一种获取firebase的方法,以便在其中查询以查找数组的value属性.

I'm struggling to find a way to get a firebase where query to find the value attribute of the array.

我想知道,如果我尝试仅将值而不是标签和值保存到Firestore中,是否会更接近可行的解决方案.

I'm wondering if I might get closer to a working solution if I try to just save the value instead of both the label and the value into firestore.

我有一个Formik表格,其中:

I have a Formik form with:

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会在其数组中记录标签和值.

I tried each of these attempts (one at a time) at getting the array to populate with a single field only - but none of them work to do that. Instead, firebase records both label and value in its array.

                            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时,我正在尝试查找类别包括健康状况的文档.

Then when I try to query firebase, I'm trying to find documents where the category includes health.

我已经尝试了下面的每个where查询,但是我无法让它们返回查询的结果(如果删除了where查询,则可以返回所有结果):

I have tried each of the where queries below but I can't get any of them to return the queried results (I can return all the results if I remove the where query):

function useHealthTerms() {
    const [healthTerms, setHealthTerms] = useState([])
    useEffect(() => {
      firebase
        .firestore()
        .collection("study")
    //.where("title", "==", "ss") 

注意-这可以找到标题.标题字段相同 级别作为类别字段

NOTE - this works to find the title. The title field is at the same level as the category field

        //.where('category', '==', 'health')
        //.where('category.value', "array-contains", 'health")
        //.where('category', 'array-contains', 'health')
        //.where('category', 'array-contains', 1)
    //.where("category.1.value", '==', 'health')
        .onSnapshot(snapshot => {
          const healthTerms = snapshot.docs.map(doc => ({
            id: doc.id,
            ...doc.data(),
          }))
          setHealthTerms(healthTerms)
        })
    }, [])
    return healthTerms
  }

我看过这篇文章,但是我不够聪明,无法从答案中获得任何意义.

I have seen this post, but I'm not clever enough to make any sense from the answer to it.

我还看到了这篇文章和贝蒂建议的答案.我已经尝试了以下查询构造的多种变体来尝试和使用这种想法,但是每次,查询形式都会出错.

I've also seen this post and the answer suggested by Betty. I've tried multiple variations on the following query construct to try and use the idea, but each time, I get an error with the form of the query.

.where(new firebase.firestore().FieldPath("category", "value"), '==', 'health')

我想知道是否可以尝试在formik中获取类别表单字段,只是为了保存option.value而不是标签和值.

I'm wondering if I can try to get the category form field in formik just to save the option.value instead of both label and value.

我看不到formik handleChange如何工作以要求它仅保存值.

I can't see how the formik handleChange works to ask it to save just the value.

即使那样,我也看不到如何查询firestore以将数组的内容用作查询参数.

Even then, I can't see how to query firestore to use the content of an array as a query parameter.

有人知道吗?

  1. 如何通过Formik表单提交到Firestore仅在自动完成中保存选项值(而不是选项标签和值)?

  1. how to save just the option value (instead of both option label and value) in the Autocomplete via formik form submission to firestore?

如何在Firestore中查询数组的内容,以查看其属性之一是否与查询匹配?

how to query the content of the array in firestore to see if one of its attributes matches the query?

这很奇怪,因为此帖子暗示了一个地方使用上面我尝试过的表单,应该可以对数组进行查询.但是,这篇文章建议采用以下格式.collection(study/[docId]).where(值","==",健康").我需要它来搜索集合中的每个文档,所以我不知道如何将这种方法应用于此问题.

It's strange because this post suggests that a where query on an array should be possible using the forms I've tried above. However, this post suggests the following format .collection(study/[docId]).where("value", "==", "health"). I need it to search each document in the collection so I don't know how to apply that approach to this problem.

以下gso_gabriel的答案提出了两个令人困惑的事情.首先,假设我使用了一个子集合.我还没有在父文档中添加以下图片以显示类别字段.我可以使用上面显示的格式对标题进行where查询,以提取值.

The answer from gso_gabriel below suggests two confusing things. First, there is an assumption that I have used a subcollection. I haven't. Adding the picture below to show the category field is in the parent document. I can do a where query on title using the formats shown above to extract the value.

其次,最令人困惑的是-它说:由于无法在数组内搜索对象".这是什么意思?是否暗示不能对类别字段中的值的内容执行查询?如果是这样,是否有资源提供有关如何查询此数据的指南?

Secondly, and the bit that is most confusing - it says: "As you can't search for a object inside an Array". What does this mean? Is it suggesting that the query cannot be performed on the content of value inside the category field? If this is the case, are there resources providing guidance for how to query this piece of data?

我还看到了此帖子-答案表明无法使用Firebase查询类别内的值.问题是我无法理解建议的替代方法.如果我正确理解了这篇文章,是否有任何教程对原理进行了扩展,以便我可以尝试找到其他查询策略?

I have also seen this post - the answer to which suggests that querying value within category is not possible using firebase. The problem is that I can't understand the suggested alternative approach. If I have understood this post correctly, are there any tutorials which expand on the principles so that I can try to find a different query strategy?

这篇文章的第一个答案还表明:无法查询类别内的值.第二个答案建议在where查询中使用其他格式-如下.

The first answer on this post also suggests that it isn't possible to query value inside category. The second answer suggests using a different format in the where query - as follows.

.where("category", "array-contains", {value: "health", label: "Health & Medical"})

答案强调了将整个数组内容添加到花括号的重要性.这行得通.

The answer stresses the importance of adding the entire array contents to the curly braces. This works.

所以-这使我回到了自动完成提交处理程序.这是一个多选字段,因此可能会选择多个值.如何在Firebase文档上将它们变成一组单个值.即使只有一个,如何更改提交处理程序,使其仅发送选择选项值,而不是同时发送值和标签?

So - this brings me back to the Autocomplete submit handler. It's a multiple select field, so there may be more than one value selected. How do I make those into a set of single values on the firebase document. Even if there were only one, how do I change the submit handler so that it only sends the select option value instead of both the value and the label?

如果不可能查询数组中的对象-如何更改提交处理程序以仅将选定的选项值添加到firebase中,而不是标签和值中? 此帖子的第一个答案中建议的解决方法是:添加一个仅包含要查询的值的字段(因此:健康).

If it isn't possible to query a object in an array - how do I change the submit handler to add just the selected option(s) values to firebase, instead of both labels and values? The suggested workaround in the first answer to this post is to add a field which just holds the value to be queried (so: health).

推荐答案

onSubmit中提交到Firebase之前,您可以更改发送数据的形状

Before submitting to firebase in onSubmit you can change the shape of the data you send

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);
    });
}}

这篇关于Formik,Material UI自动完成和Firestore-在哪里查询以找到数组参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆