Mel*_*Mel 3 javascript firebase google-cloud-firestore formik
我有一个表格。表单中的字段之一是字段数组 - 用于可重复字段。除此字段外,所有其他表单字段都存储在单个集合(父集合)中。
父集合有一个用于字段数组的数组,该数组保存每个重复条目的值,存储在子集合(子集合)中。
当我编写 firestore 提交时,我试图将要提交给父集合的字段与要提交给子集合的字段分开。
我的尝试如下。
<Formik
initialValues={{ term: "", category: [], relatedTerms: [], }}
onSubmit={(values, { setSubmitting }) => {
setSubmitting(true);
firestore.collection("glossary").doc().set({
term: values.term,
category: values.category,
createdAt: firebase.firestore.FieldValue.serverTimestamp()
}),
firestore.collection("glossary").doc().collection('relatedTerms').doc().set({
dataType: values.dataType,
title: values.Title,
description: values.description,
})
.then(() => {
setSubmitionCompleted(true);
});
}}
Run Code Online (Sandbox Code Playgroud)
这会产生一个错误,指出:
第 120:22 行:期望赋值或函数调用,却看到一个表达式 no-unused-
另外,如何在子集合的提交处理程序中知道父集合的文档引用?
我看过这篇文章,它试图在 2 个集合中使用相同的数据(同样关注查找 ID)。
我也看过这个博客,它展示了如何在子集合中使用“输入”作为参考,并且似乎有一种方法可以将它们附加到文档 ID - 但该博客没有显示输入是如何定义的。我看不出如何应用该示例。
作为参考,下面列出了带有可重复表单字段数组(在单独的表单中)的主表单。
主要形式
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,
InputLabel,
FormControlLabel,
TextField,
Typography,
Box,
Grid,
Checkbox,
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,
} from 'formik-material-ui';
import RelatedTerms from "./Form2";
const allCategories = [
{value: 'one', label: 'I'},
{value: 'two', label: 'C'},
];
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 Glossary(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 Term
</Button>
<Dialog
open={open}
onClose={handleClose}
aria-labelledby="form-dialog-title"
>
{!isSubmitionCompleted &&
<React.Fragment>
<DialogTitle id="form-dialog-title">Create a defined term</DialogTitle>
<DialogContent>
<DialogContentText>
Your contribution to the research community is appreciated.
</DialogContentText>
<Formik
initialValues={{ term: "", definition: "", category: [], context: "", relatedTerms: [] }}
onSubmit={(values, { setSubmitting }) => {
setSubmitting(true);
firestore.collection("glossary").doc().set({
term: values.term,
definition: values.definition,
category: values.category,
context: values.context,
createdAt: firebase.firestore.FieldValue.serverTimestamp()
}),
firestore.collection("glossary").doc().collection('relatedTerms').doc().set({
dataType: values.dataType,
title: values.title,
description: values.description,
})
.then(() => {
setSubmitionCompleted(true);
});
}}
validationSchema={Yup.object().shape({
term: Yup.string()
.required('Required'),
definition: Yup.string()
.required('Required'),
category: Yup.string()
.required('Required'),
context: Yup.string()
.required("Required"),
// relatedTerms: Yup.string()
// .required("Required"),
})}
>
{(props) => {
const {
values,
touched,
errors,
dirty,
isSubmitting,
handleChange,
handleBlur,
handleSubmit,
handleReset,
} = props;
return (
<form onSubmit={handleSubmit}>
<TextField
label="Term"
name="term"
// className={classes.textField}
value={values.term}
onChange={handleChange}
onBlur={handleBlur}
helperText={(errors.term && touched.term) && errors.term}
margin="normal"
style={{ width: "100%"}}
/>
<TextField
label="Meaning"
name="definition"
multiline
rows={4}
// className={classes.textField}
value={values.definition}
onChange={handleChange}
onBlur={handleBlur}
helperText={(errors.definition && touched.definition) && errors.definition}
margin="normal"
style={{ width: "100%"}}
/>
<TextField
label="In what context is this term used?"
name="context"
// className={classes.textField}
multiline
rows={4}
value={values.context}
onChange={handleChange}
onBlur={handleBlur}
helperText={(errors.context && touched.context) && errors.context}
margin="normal"
style={{ width: "100%"}}
/>
<Box margin={1}>
<Field
name="category"
multiple
component={Autocomplete}
options={allCategories}
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>
<FieldArray name="relatedTerms" component={RelatedTerms} />
<Button type="submit">Submit</Button>
<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">Thanks!</DialogTitle>
<DialogContent>
<DialogContentText>
</DialogContentText>
<DialogActions>
<Button
type="button"
className="outline"
onClick={handleClose}
>
Close
</Button>
{/* <DisplayFormikState {...props} /> */}
</DialogActions>
</DialogContent>
</React.Fragment>}
</Dialog>
</React.Fragment>
);
}
export default Glossary;
Run Code Online (Sandbox Code Playgroud)
可重复表单字段的字段数组
import React from "react";
import { Formik, Field } from "formik";
import Button from '@material-ui/core/Button';
const initialValues = {
dataType: "",
title: "",
description: "",
};
const dataTypes = [
{ value: "primary", label: "Primary (raw) data" },
{ value: "secondary", label: "Secondary data" },
];
class DataRequests extends React.Component {
render() {
const {form: parentForm, ...parentProps} = this.props;
return (
<Formik
initialValues={initialValues}
render={({ values, setFieldTouched }) => {
return (
<div>
{parentForm.values.relatedTerms.map((_notneeded, index) => {
return (
<div key={index}>
<div className="form-group">
<label htmlFor="relatedTermsTitle">Title</label>
<Field
name={`relatedTerms.${index}.title`}
placeholder="Add a title"
className="form-control"
onChange={e => {
parentForm.setFieldValue(
`relatedTerms.${index}.title`,
e.target.value
);
}}
></Field>
</div>
<div className="form-group">
<label htmlFor="relatedTermsDescription">
Description
</label>
<Field
name={`relatedTerms.${index}.description`}
component="textarea"
rows="10"
placeholder="Describe use"
className="form-control"
onChange={e => {
parentForm.setFieldValue(
`relatedTerms.${index}.description`,
e.target.value
);
}}
></Field>
</div>
<Button
onClick={() => parentProps.remove(index)}
>
Remove
</Button>
</div>
);
})}
<Button
variant="primary"
size="sm"
onClick={() => parentProps.push(initialValues)}
>
Add another
</Button>
</div>
);
}}
/>
);
}
}
export default DataRequests;
Run Code Online (Sandbox Code Playgroud)
下一个尝试
当我尝试下面 BrettS 提出的建议时,我收到一条控制台警告,内容为:
警告:从 submitForm() FirebaseError 中捕获了未处理的错误:使用无效数据调用的函数 DocumentReference.set()。不支持的字段值:未定义(在字段标题中找到)
我看过这篇文章,讨论了如何构建要在尝试中使用的对象,但我不知道如何将这些想法应用于这个问题。
我尝试过的另一个尝试如下:
onSubmit={(values, { setSubmitting }) => {
setSubmitting(true);
// const newGlossaryDocRef = firestore.collection("glossary").doc();
// newGlossaryDocRef.set({
// term: values.term,
// definition: values.definition,
// category: values.category,
// context: values.context,
// createdAt: firebase.firestore.FieldValue.serverTimestamp()
// });
// newGlossaryDocRef.collection('relatedTerms').doc().set({
// // dataType: values.dataType,
// title: values.title,
// // description: values.description,
// })
const glossaryDoc = firestore.collection('glossary').doc()
const relatedTermDoc = firestore
.collection('glossary')
.doc(glossaryDoc.id) // <- we use the id from docRefA
.collection('relatedTerms')
.doc()
var writeBatch = firestore.batch();
writeBatch.set(glossaryDoc, {
term: values.term,
category: values.category,
createdAt: firebase.firestore.FieldValue.serverTimestamp(),
});
writeBatch.set(relatedTermDoc, {
// dataType: values.dataType,
title: values.Title,
// description: values.description,
});
writeBatch.commit().then(() => {
// All done, everything is in Firestore.
})
.catch(() => {
// Something went wrong.
// Using firestore.batch(), we know no data was written if we get here.
})
.then(() => {
setSubmitionCompleted(true);
});
}}
Run Code Online (Sandbox Code Playgroud)
当我尝试这个时,我得到了同样的警告。它说:
警告:从 submitForm() FirebaseError: 使用无效数据调用的函数 WriteBatch.set() 中捕获了未处理的错误。不支持的字段值:未定义(在字段标题中找到)
这种拆分参考格式出现另一个错误,它说:
警告:列表中的每个孩子都应该有一个唯一的“key”道具。
我认为这一定与引用的新结构有关 - 但我不知道如何解决它。
下一次尝试
当我尝试 Brett 修订后的建议答案时,我有:
onSubmit={(values, { setSubmitting }) => {
setSubmitting(true);
// firestore.collection("glossary").doc().set({
// ...values,
// createdAt: firebase.firestore.FieldValue.serverTimestamp()
// })
// .then(() => {
// setSubmitionCompleted(true);
// });
// }}
const newDocRef = firestore.collection("glossary").doc()
// auto generated doc id saved here
let writeBatch = firestore.batch();
writeBatch.set(newDocRef,{
term: values.term,
definition: values.definition,
category: values.category,
context: values.context,
createdAt: firebase.firestore.FieldValue.serverTimestamp()
});
writeBatch.set(newDocRef.collection('relatedTerms').doc(),{
// dataType: values.dataType,
title: values.title,
// description: values.description,
})
writeBatch.commit()
.then(() => {
setSubmitionCompleted(true);
});
}}
Run Code Online (Sandbox Code Playgroud)
请注意,我在 relatedTerms 文档中评论了除 title 属性之外的所有内容,以便我可以查看这是否有效。
它没有。表单仍然呈现,当我尝试按提交时,它只是挂起。控制台中不会生成错误消息,但会生成一条警告消息,内容为:
0.chunk.js:141417 警告:从 submitForm() FirebaseError 捕获未处理的错误:使用无效数据调用函数 WriteBatch.set()。不支持的字段值:未定义(在字段标题中找到)
当我用谷歌搜索这个时 - 从这篇文章看来,在 relatedTerm 集合中定义父文档 id 的方式可能存在问题。
我还想知道是否可能需要为每个集合单独定义和初始化初始值?
当我尝试控制台记录表单条目的值时,我可以看到捕获了一个值为 title 的对象。表单的初始值包括一个名为 relatedTerms 的数组(初始值:[])。
在尝试将其发送到 firestore 之前,我可能需要做一些事情将该数组转换为其中的值。我该怎么做?
我链接的帖子将其分为 2 个步骤,但我太慢了,无法弄清楚他们在做什么或如何自己做。奇怪的是,当我不尝试在 firestore 集合之间拆分表单值时不会出现这个问题 - 如果我只使用单个文档,那么这里需要发生的任何事情都是默认完成的。
我不确定我想要做的是否是 firestore 文档在自定义对象部分中描述的内容。我注意到上面的添加数据示例显示了添加一个数组,而没有采取任何步骤在提交之前将数组中的项目转换为数据类型。我不确定这是否是正确的查询方式,因为如果我不尝试在集合之间拆分数据,则提交工作正常。
下一次
每次调用 时doc(),都会生成对随机生成的新文档的引用。这意味着您的第一次调用firestore.collection("glossary").doc()将生成一个新 ID,以及随后的调用。如果要重用文档引用,则必须将其存储在变量中。
const firstDocRef = firestore.collection("glossary").doc()
firstDocRef.set(...)
Run Code Online (Sandbox Code Playgroud)
稍后使用相同的变量:
const secondDocRef = firstDocRef.collection('relatedTerms').doc()
secondDocRef.set(...)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
663 次 |
| 最近记录: |