Search code examples
firebasevue.jsgoogle-cloud-firestorevue-componentinformation-retrieval

Vue: [Vue warn]: Error in render: "TypeError: product.data is not a function"


I am trying to retrieve the data from cloud firestore database. But I got an error,

[Vue warn]: Error in render: "TypeError: product.data is not a function"

I want to show the each product name and price in my table.

But I have no idea why this issue comes up. So I hope somebody can help me out.

If I don't use data() in the vue template, I can see all the data as I expected.

<template>
 <h3>Product List</h3>
            <div class="table-responsive">
              <table class="table">
              <thead>
                <tr>
                  <th>Name</th>
                  <th>Price</th>
                  <th>Modify</th>
                </tr>
              </thead>

              <tbody>
                <tr v-for="(product, index) in products" :key="index">
                  <td>{{ product.data().name }}</td>
                  <td>{{ product.data().price }}</td>
                  <td>
                    <button @click="editProduct(product)" class="btn btn-primary">Edit</button>
                    <button @click="deleteProduct(product.id)" class="btn btn-danger">Delete</button>
                  </td>
                </tr>
              </tbody>
            </table>
            </div>
</template>
<script>

import { fb, db } from '../firebase'
 

export default {
  name: 'Products',
  props: {
    msg: String
  },
  data () {
    return {
      products: [],
      product: {//object
        name: null,
        price: null
      }
    }
  },
  methods: {
    editProduct(product) {
      $('#edit').modal('show') 
    },
    readData() {
      
      db.collection("products").get().then((querySnapshot) => {
        querySnapshot.forEach((doc) => {
          this.products.push(doc.data());
        });
      });
    },
    
    saveData() {
      // Add a new document with a generated id.
      db.collection("products").add(this.product)
      
      .then((docRef) =>  {
          console.log("Document written with ID: ", docRef.id);
          this.product.name = "",
          this.product.price = ""
          this.readData()
      })
      .catch(function(error) {
          console.error("Error adding document: ", error);
      });
    }
  },
  created() {
      this.readData();
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">

</style>

Solution

  • I will have to agree with @Mostafa, the naming convention is not very readable. Your error is telling you that you are trying to invoke a function that is not a function or does not exist in your data.

    Change:

    <td>{{ product.data().name }}</td>
    <td>{{ product.data().price }}</td>
    

    To:

    <td>{{ product.name }}</td>
    <td>{{ product.price }}</td>
    

    This should fix it, as you are iterating over the products list (of which isn't clear), so i advise you should change:

    <tr v-for="(product, index) in products" :key="index">
      <td>{{ product.name }}</td>
      <td>{{ product.price }}</td>
      <td>
        <button @click="editProduct(product)" class="btn btn-primary">Edit</button>
        <button @click="deleteProduct(product.id)" class="btn btn-danger">Delete</button>
    

    To:

     <tr v-for="(productItem, index) in products" :key="index">
      <td>{{ productItem.name }}</td>
      <td>{{ productItem.price }}</td>
      <td>
        <button @click="editProduct(productItem)" class="btn btn-primary">Edit</button>
        <button @click="deleteProduct(productItem.id)" class="btn btn-danger">Delete</button>