nicholasfc
nicholasfc

Reputation: 195

Firebase toDate giving undefined error on Vue Component

I'm trying to use the toDate() function to convert a timestamp into a readable date using the toDate() from firestore and moment.js to convert to the desired date format.

It all looks good until I use the toDate function and I get an error [

Vue warn]: Error in render: "TypeError: member.dateAdded is undefined"

And I can't see why the error is happening since I'm using converting date on other part of my Vue component and I'm not getting this error.

Here is the component I'm getting the error. As you can see, I'm using the toDate before the table without problem but the one inside the table is giving me the error. When I don't use the function I get this

Timestamp(seconds=1577548891, nanoseconds=834000000)

<template>
  <div>
    <v-snackbar v-model="snackbar">
      <span>Player Added!</span>
      <v-btn color="blue" text @click="snackbar = false">Close</v-btn>
    </v-snackbar>
    <h3 class="font-weight-medium text-center pa-3 ma-3 display-1">Member List</h3>
    <template v-if="isMember || isAdmin">
      <p
        v-for="log in logs"
        :key="log.id"
        class="body-2 text-right"
      >Last Point given @ {{log.time.toDate() | formatDate}}</p>
      <p>
        <v-simple-table fixed-header height="70vh">
          <template v-slot:default>
            <thead>
              <tr>
                <th class="text-left title">Name</th> 
                <th class="text-left title">Added</th>
              </tr>
            </thead>
            <tbody>
              <tr v-for="(member, index) in members" :key="index">
                <td>{{member.name}}</td>
                <td>{{member.dateAdded.toDate() | formatDate}}</td>
              </tr>
            </tbody>
          </template>
        </v-simple-table>
      </p>
    </template>
  </div>
</template>

<script>
import { db, fv, tstp } from "../data/firebaseInit";
import firebase from "firebase/app";
import Popup from "../components/Popup";
import moment from "moment";
export default {
  components: { Popup },
  data() {
    return {
      isAdmin: false,
      isMember: false,
      snackbar: false,
      members: [],
      logs: [],
      user: null
    };
  },
  filters: {
    formatDate: function(value) {
      if (value) {
        return moment(value).format("DD/MMM/YYYY HH:mm");
      }
    }
  },
  created() {
    this.fetchDb();
  },
  methods: {
    fetchDb() {
      db.collection("members")
        .orderBy("name")
        .onSnapshot(snap => {
          const members = [];
          snap.forEach(doc => {
            let newPlayer = doc.data();
            newPlayer.id = doc.id;
            members.push(newPlayer);
          });
          this.members = members;
          this.user = firebase.auth().currentUser.displayName;
        });
      db.collection("pointLog")
        .orderBy("time", "desc")
        .limit(1)
        .onSnapshot(snap => {
          const logs = [];
          snap.forEach(doc => {
            let newLog = doc.data();
            newLog.id = doc.id;
            logs.push(newLog);
          });
          this.logs = logs;
        });
    }
    }
  }
};
</script>

And here is the component that is adding the timestamp to the firestore

<template>
  <v-dialog max-width="600px" v-model="dialog" v-if="isAdmin">
    <template v-slot:activator="{ on }">
      <v-icon color="green" x-large bottom right v-on="on">mdi-plus-circle</v-icon>
    </template>

    <v-card>
      <v-toolbar flat>
        <v-toolbar-title>Add Player</v-toolbar-title>
      </v-toolbar>
      <v-card-text>
        <v-form>
          <v-text-field required label="Player Name" v-model="name"></v-text-field>
          <v-btn text class="success" @click="onSubmit()">Add Player</v-btn>
        </v-form>
      </v-card-text>
    </v-card>
  </v-dialog>
</template>

<script>
import { db, tstp } from "../data/firebaseInit";
import firebase from "firebase/app";
export default {
  data() {
    return {
      name: null,
    };
  },
  submited: {
    name: "",
    dialog: "",
  },
  methods: {
    onSubmit() {
      db.collection("members")
        .add({
          name: this.name,
          dateAdded: tstp.fromDate(new Date()),
        })
        .then(() => {
          this.dialog = false;
          this.$emit("playerAdded");
        })
        .catch(err => console.log(err));
    }
  }
};
</script>

<style>
</style>

Could anyone shed my some light on this?

Upvotes: 0

Views: 520

Answers (1)

Renaud Tarnec
Renaud Tarnec

Reputation: 83163

This is most probably because, for some elements of the members array, there is no dateAdded value.

Without seeing your data it is difficult to know what is the exact reason, but one of the most likely possible causes is documents in your members collection without a dateAdded field;

One possible way to deal with this problem is to do as follows:

<td v-if="member.dateAdded">{{member.dateAdded.toDate() | formatDate}}</td>
<td v-else>-</td>

In addition, note that it would be better to use the get() method instead of the onSnapshot() one, since you only want to query once the Firestore collections.

You could chain the two calls as follows:

fetchDb() {
  db.collection("pointLog")
    .orderBy("time", "desc")
    .limit(1)
    .get()
    .then(snap => {
      const logs = [];
      snap.forEach(doc => {
        let newLog = doc.data();
        newLog.id = doc.id;
        logs.push(newLog);
      });
      this.logs = logs;

      return db
        .collection("members")
        .orderBy("name")
        .get();
    })
    .then(snap => {
      const members = [];
      snap.forEach(doc => {
        let newPlayer = doc.data();
        newPlayer.id = doc.id;
        members.push(newPlayer);
      });
      this.members = members;
      this.user = firebase.auth().currentUser.displayName;
    });
}

Upvotes: 2

Related Questions