尝试在 vuejs 中更新 firebase 文档时,我无法解决此未定义字段问题
Posted
技术标签:
【中文标题】尝试在 vuejs 中更新 firebase 文档时,我无法解决此未定义字段问题【英文标题】:I cannot fix this undefined field issue when trying to update firebase document in vuejs 【发布时间】:2022-01-20 07:04:21 【问题描述】:我正在尝试通过不断收到此错误来更新我的 firebase 文档'
FirebaseError:使用无效数据调用函数 DocumentReference.update()。不支持的字段值:未定义(在文档课程/1wY9RjpYtNeEDtuaeXmh 中的字段 id 中找到)
这是我的 GameForm vue 组件代码:
<template>
<div class="game-form">
<v-btn @click="dialog = !dialog" color="primary" v-if="!course">Add new game</v-btn>
<v-btn @click="dialog = !dialog; setData()" color="primary" v-else>Edit game</v-btn>
<v-dialog v-model="dialog" persistent >
<v-card>
<v-card-title v-if="!course">Add new game</v-card-title>
<v-card-title v-else>Edit game</v-card-title>
<v-card-text>
<v-form
v-model="valid"
lazy-validation
ref="form"
>
<v-text-field
v-model="subject"
:rules="fieldRules"
label="Subject"
required
outline
>
</v-text-field>
<v-textarea
v-model="description"
:rules="fieldRules"
label="Game developer"
outlined
required
>
</v-textarea>
<v-text-field
v-model="duration"
:rules="fieldRules"
label="Duration"
outlined
required
>
</v-text-field>
<v-textarea
v-model="payment"
:rules="fieldRules"
label="Payment"
outlined
required
>
</v-textarea>
<v-textarea
v-model="years_exp"
:rules="fieldRules"
label="Experience"
outlined
required
>
</v-textarea>
<v-textarea
v-model="tutor"
:rules="fieldRules"
label="Tutor"
outlined
required
>
</v-textarea>
<v-textarea
v-model="amount"
:rules="fieldRules"
label="Amount"
outlined
required
>
</v-textarea>
<!-- <v-textarea
v-model="years_exp"
:rules="fieldRules"
label="Game description"
outlined
required
>
</v-textarea> -->
<v-file-input
accept="image/*"
label="File input"
v-model="file"
show-size
>
</v-file-input>
<p>Current image: <a v-if="oldImage" :href="oldImage">link</a></p>
<v-btn
elevation="2"
color="primary"
@click="storeGame"
:loading="isLoading"
v-if="!course"
>
Store
</v-btn>
<v-btn
elevation="2"
color="primary"
@click="updateGame"
:loading="isLoading"
v-else
>
Update
</v-btn>
</v-form>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
color="blue darken-1"
text
@click="dialog = false"
>
Close
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</div>
</template>
<script>
import coursesCollection, auth, storage from '../firebase'
export default
name: 'GameForm',
props: ['course', 'index'],
data()
return
isLoading: false,
valid: false,
dialog: false,
subject: '',
description: '',
tutor: '',
payment: 0,
duration: '',
amount: 0,
years_exp: 0,
file: null,
fieldRules: [
v => !!v || 'this field is required'
],
oldImage: ''
,
methods:
resetForm()
this.$refs.form.reset()
,
async storeGame()
try
this.isLoading = false
// upload file
const fileRef = 'uploads/courses/' + this.file.name
const snapshot = await storage.ref(fileRef).put(this.file)
let data =
userId: auth.currentUser.uid,
subject: this.subject,
description: this.description,
tutor: this.tutor,
payment: this.payment,
duration: this.duration,
amount: this.amount,
years_exp: this.years_exp,
image: fileRef
const doc = await coursesCollection.add(data)
this.$emit('course:added', data)
await this.resetForm()
this.isLoading = false
this.dialog = false
catch(e)
console.log(e)
,
async updateGame()
try
this.isLoading = false
let data =
id: this.id,
userId: auth.currentUser.uid,
subject: this.subject,
description: this.description,
tutor: this.tutor,
payment: this.payment,
duration: this.duration,
amount: this.amount,
years_exp: this.years_exp,
if(this.file)
// delete oldImage
const fileRefOld = this.course.img
await storage.ref(fileRefOld).delete()
// upload file
const fileRef = 'uploads/courses/' + this.file.name
const snapshot = await storage.ref(fileRef).put(this.file)
data.image = fileRef
else
data.image = this.course.image
const doc = await coursesCollection.doc(this.course.id).update(data)
// await this.resetForm()
this.isLoading = false
this.dialog = false
data.index = this.index
// this.$emit('course:updated', data)
alert('Game updated!')
catch(e)
// console.log(this.course.id);
console.log(e)
,
setData()
if(this.course)
this.subject = this.course.subject,
this.description = this.course.description,
this.tutor = this.course.tutor,
this.payment = this.course.payment,
this.duration = this.course.duration,
this.amount = this.course.amount,
this.years_exp = this.course.years_exp,
this.oldImage = this.course.image
,
mounted()
this.setData()
</script>
这是我的仪表板页面
<template>
<div class="dashboard">
<h1>Hi, userProfile.name </h1>
<GameForm @course:added="addGame" />
<v-row>
<v-col md="4" v-for="(course, index) in courses" :key="course.id">
<v-card>
<v-img
v-if="course.image"
:src="course.image"
lazy-src="https://via.placeholder.com/250"
>
</v-img>
<v-card-title> course.subject </v-card-title>
<v-card-text>
<p class="subtitle-1">tutor: course.tutor </p>
<p class="subtitle-1">duration: course.duration </p>
<p> course.description </p>
</v-card-text>
<v-card-actions>
<GameForm :course="course" :index="index" @course:updated="updateGame" />
<v-btn color="red" @click="deleteConfirm(course.id, course.subject)" text>Delete</v-btn>
</v-card-actions>
</v-card>
</v-col>
</v-row>
<v-dialog
v-model="deleteDialog"
max-
>
<v-card>
<v-card-title class="headline">
Delete Game?
</v-card-title>
<v-card-text>Are you sure you want to delete <b> pTitle </b>?</v-card-text>
<v-card-actions>
<v-btn text color="red" @click="deleteGame">Delete</v-btn>
<v-btn @click="deleteDialog = false" text color="secondary">Close</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<br><br><br><br><br>
<v-row>
<v-layout>
<v-flex xs12 sm6>
<v-card hover>
<v-responsive
>
<!-- <v-img
src="https://raw.githubusercontent.com/ijklim/simon-game/gh-pages/assets/img/bg--game-pad.jpg"
>
</v-img> -->
<Play />
</v-responsive>
<v-card-title>
<h2>v-card-title</h2>
</v-card-title>
<v-card-text>
line 1<br>
line 2<br>
line 3
</v-card-text>
<v-card-actions>
<v-btn color=success>Click #1</v-btn>
<v-btn text color=primary>Click #2</v-btn>
<v-spacer></v-spacer>
<v-btn icon><v-icon>b</v-icon></v-btn>
</v-card-actions>
</v-card>
</v-flex>
</v-layout>
</v-row>
</div>
</template>
<script>
import mapState from 'vuex'
import GameForm from '@/components/GameForm'
import Play from './Play'
import auth, storage, coursesCollection from '../firebase'
export default
components:
GameForm,
Play
,
data()
return
courses: [],
pId: null,
pTitle: null,
deleteDialog: false,
userProfile:
,
computed:
...mapState(['userProfile'])
,
methods:
async addGame(doc)
let img = ''
if(doc.image)
img = await storage.ref().child(doc.image).getDownloadURL()
this.courses.push(
id: doc.id,
subject: doc.subject,
description: doc.description,
tutor: doc.tutor,
payment: doc.payment,
duration: doc.duration,
amount: doc.amount,
years_exp: doc.years_exp,
image: img,
img: doc.image
)
,
async updateGame(doc)
let img = ''
if(doc.image)
img = await storage.ref().child(doc.image).getDownloadURL()
if (doc.id)
console.log('u', doc.tutor),
this.courses.splice(doc.index, 0,
id: doc.id,
subject: doc.subject,
description: doc.description,
tutor: doc.tutor,
payment: doc.payment,
duration: doc.duration,
amount: doc.amount,
years_exp: doc.years_exp,
image: img,
img: doc.image
)
,
async getGames()
try
const querySnapshot = await coursesCollection.where('userId', '==', auth.currentUser.uid).get()
querySnapshot.forEach( async (doc) =>
let img = ''
if(doc.data().image)
img = await storage.ref().child(doc.data().image).getDownloadURL()
this.courses.push(
id: doc.data().id,
subject: doc.data().subject,
description: doc.data().description,
tutor: doc.data().tutor,
payment: doc.data().payment,
duration: doc.data().duration,
amount: doc.data().amount,
years_exp: doc.data().years_exp,
image: img,
img: doc.data().image
)
)
catch(e)
console.log(e)
,
async deleteConfirm(id, subject)
this.deleteDialog = true
this.pId = id
console.log(this.pId)
this.pTitle = subject
,
async deleteGame()
try
await coursesCollection.doc(this.pId).delete()
alert('Course deleted!')
// remove game from array
this.courses.splice(this.courses.findIndex(x => x.id == this.pId), 1)
this.deleteDialog = false
// reset
this.pId = null
this.pTitle = null
catch(e)
console.log(e)
,
async mounted()
await this.getGames()
</script>
这是我的 store.js 文件:
import Vue from 'vue'
import Vuex from 'vuex'
import * as fb from '../firebase'
import router from '../router/index'
Vue.use(Vuex)
export default new Vuex.Store(
state:
userProfile: ,
isAuthenticated: false
,
mutations:
setUserProfile(state, val, authState)
state.isAuthenticated = !state.isAuthenticated
state.userProfile = val
,
actions:
async register( dispatch, form)
// sign up user
const user = await fb.auth.createUserWithEmailAndPassword(form.email, form.password)
// create user profile object
await fb.usersCollection.doc(user.uid).set(
name: form.name
)
// fetch user profile
dispatch('fetchUserProfile', user)
,
async login( dispatch , form)
// sign in user
const user = await fb.auth.signInWithEmailAndPassword(form.email, form.password)
// fetch user profile
dispatch('fetchUserProfile', user)
,
async fetchUserProfile( commit , user)
// fetch user profile
const userProfile = await fb.usersCollection.doc(user.uid).get()
// set user profile
commit('setUserProfile', userProfile.data())
// change route or redirect
router.push('/dashboard')
,
async logout( commit )
await fb.auth.signOut()
commit('setUserProfile', )
router.push('/')
,
modules:
)
当我签入开发工具时,userProfile、pId、PTitle 都是未定义的。
我是 vue 和 firebase 的新手,所以我被卡住了。请问可以指导我吗?
【问题讨论】:
【参考方案1】:这是因为您传递给await coursesCollection.doc(this.course.id).update(data)
的data
对象中的属性之一是未定义的。
您应该调试您的代码并找出该对象的哪些属性未定义:
let data =
id: this.id,
userId: auth.currentUser.uid,
subject: this.subject,
description: this.description,
tutor: this.tutor,
payment: this.payment,
duration: this.duration,
amount: this.amount,
years_exp: this.years_exp,
【讨论】:
感谢@Renaud。我一遍又一遍地检查,我想我在数据对象中定义了所有这些。我只是无法自己弄清楚。我已经编辑了我的问题以包含更多代码来进一步解释我的问题。再次感谢。 @AbarugoGoodness Renaud 几乎拥有它,id: this.id
是您未定义的值 - “在文档中的字段 id 中找到”。它应该是id: this.course.id
,因为在您的setData()
方法中,您不会像使用其他属性那样从this.course
复制它。
哦,我再次检查,'id' 未定义。我如何得到它?有没有不同的方法来获取它,因为我成功检索了其他字段。再次感谢。
非常感谢,@samthecodingman,我将其更改为 >this.course.id,但未定义
@AbarugoGoodness 看起来您从未在文档数据中附加了 ID。您需要使用const docRef = coursesCollection.doc(); data.id = docRef.id; const doc = await docRef.set(data);
,而不是const doc = await coursesCollection.add(data)
。以上是关于尝试在 vuejs 中更新 firebase 文档时,我无法解决此未定义字段问题的主要内容,如果未能解决你的问题,请参考以下文章
Vuejs 和 Firebase 存储问题。未捕获的类型错误:存储不是函数
Vuejs 和 Firestore - 如何在 Firestore 中的数据更改时进行更新
带有 vuejs 的 Firebase 数据库:default.collection 不是函数