简体   繁体   中英

How to delete nested Firebase data with Vue.js

I am attempting to build a Vue.js component that enables deleting of nested Firebase data. My component currently looks like the following:

<v-flex v-for="user in users" :key="user.id" xs12 md12>
  <v-layout row wrap>
    <v-flex v-for="newUser in user.gallery" :key="newUser.id" xs12 sm6 md3>
      <v-img :src="newUser.image" />
      <v-btn @click="deleteImg(newUser.id)">x</v-btn>
    </v-flex>
  </v-layout>
</v-flex>

This component uses a v-for directive to first loop through all Firebase items returned to the users array. The second v-for directive loops through all of the images inside a nested Firebase array called gallery . The delete button is intended to target the id of each image (newUser.id) inside the nested gallery array. Here is the deleteImg() method:

    deleteImg (img) {
      db.collection('users').doc(img).delete()
    }

When I click the deleteImg() button, I get the following handler error:

Function CollectionReference.doc() requires its first argument to be of type non-empty string, but it was: undefined

How can I adjust the deleteImg() handler to properly target images based on id in the nested array? Thanks!

******REVISION******

Here is the full code for a better example of what I am trying to accomplish. Basically, this component is set up to push new input into an array called events (which already exists as a document field in Firebase), and then then return those array items in user.events to the screen. As you can see in the screenshot below, those inputted items are stored in the events array. Those array items render on the screen just fine. I am attempting to delete those array items, but am not sure how to properly target them. How can I configure the deleteInput() method to target those array items?

<template>
  <div class="input">
    <input v-model="newInput" />
    <button @click.prevent="addInput()">submit</button>
    <br><br>
    <div v-for="user in users" :key="user.id">
      <div v-for="newUser in user.events" :key="newUser.id">
        <h3>{{ newUser.name }}</h3>
        <button @click="deleteInput(newUser.id)">x</button>
      </div>
    </div>
  </div>
</template>

<script>
import firebase from 'firebase'
import { db } from '@/main'
export default {
  name: 'HelloWorld',
  data: () => ({
    newInput: null,
    users: []
  }),
  mounted () {
    this.getData()
  },
  methods: {
    async getData () {
      let snapshot = await db.collection('users').get()
      const users = []
      snapshot.forEach(doc => {
        let appData = doc.data()
        appData.id = doc.id
        users.push(appData)
      })
      this.users = users
    },
    async addInput () {
      let finalInput = this.newInput
      let querySnapshot = await db.collection('users').where('user_id', '==', firebase.auth().currentUser.uid).get()
        querySnapshot.forEach(function(doc) {
          doc.ref.update({'events': firebase.firestore.FieldValue.arrayUnion({
            'name': finalInput
          })
        })
      })
      this.newInput = ''
      this.getData()
    },
    deleteInput (item) {
      db.collection('users').doc(item).delete()
    }
  }
}
</script>

在此处输入图像描述

There are two pieces of code in your question (somehow two linked but different questions): an initial one and one after the REVISION.

Let's first give the answer for the initial question: with your Vue.js component code you need to have a users array that looks like:

  users: [
    {
      id: 1,
      gallery: [
        { id: 11, image: "http://...image1.jpg" },
        { id: 12, image: "http://...image2.jpg" },
        { id: 13, image: "http://...image3.jpg" }
      ]
    },
    {
      id: 2,
      gallery: [
        { id: 21, image: "http://...image1.jpg" },
        { id: 22, image: "http://...image2.jpg" },
        { id: 23, image: "http://...image3.jpg" }
      ]
    }
  ]

It means you have to "construct" your Firestore documents in such a way they return an array with this format.


For the second problem (after the REVISION sub-title):

You should use the optional second argument of v-for to get the index of the current item and call the deleteInput() with this index value plus the user.id , as follows:

<div v-for="user in users" :key="user.id">
  <div v-for="(newUser, index) in user.events" :key="newUser.id">
    <h3>{{ newUser.name }}</h3>
    <button @click="deleteInput(user.id, index)">x</button>
  </div>
</div>

Then in deleteInput() you need to

either

overwrite the events array for the user (with id == user.id) with a new events array, in which you have deleted the element at position index ,

or

use the arrayRemove() method with the entire object (events, email, name, etc...).

I would opt for the first approach.

Note that depending on your exact use case you may have to do that in a transaction, to be sure the events array was not modified between the initial read and the modifciation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM