4

So when I try to run my parent component 'Dashboard' in my browser. The child component 'ChartUsage' throws an error in my console: [Vue warn]: Error in created hook: "TypeError: Cannot convert undefined or null to object" When I try to debug I see that the prop: userSubmitsProp, just return an empty array. So that's also strange. But I can't figure out why. Can anyone help me out?

Parent component that send the prop: userSubmitsProp:

<template>
  <div class="dashboard">
    <cards :userDataProp="currentUserData"/>
    <chartusage :userSubmitsProp="previousSubmits" />
  </div>
</template>

<script>
import db from '@/firebase/init'
import firebase from 'firebase'
import moment from 'moment'
import Chartusage from '@/components/dashboard/ChartUsage'
import Cards from '@/components/dashboard/Cards'

export default {
  name: 'Dashboard',
  components: {
    Chartusage,
    Cards
  },
  data () {
    return {
      currentUserData: {},
      previousSubmits: []
    }
  },
  created () {
    let user = firebase.auth().currentUser

    // find the user record
    db.collection('users').where('user_id', '==', user.uid).get()
      .then(snapshot => {
        snapshot.forEach((doc) => {
          let userData = doc.data()
          userData.timestamp = moment(doc.data().timestamp).format('lll')
          this.currentUserData = userData
        })
      })
      .then(() => {
        // fetch the user previous submits from the firestore
        db.collection('submits').where('user', '==', this.currentUserData.alias).get()
          .then(snapshot => {
            snapshot.forEach(doc => {
              let submit = doc.data()
              submit.id = doc.id
              submit.timestamp = moment(doc.data().timestamp).format('lll')
              this.previousSubmits.push(submit)

              // sort previousSubmits array by date
              this.previousSubmits.sort((a, b) => {
                a = new Date(a.timestamp)
                b = new Date(b.timestamp)
                return b - a
              })
              console.log(this.previousSubmits)
            })
          })
      })
  }
}
</script>

<style>
</style>

Child component that receives the userSubmitsProp prop to make a chart with it:

<template>
  <div class="check-usage">
    <div class="row">
      <div class="col s12">
        <div class="chart">
          <chartjs-line
            :fill="true"
            :datalabel="'My household usage'"
            :labels="labels"
            :data="dataset"
            :bordercolor="'#1976D2'"
            :backgroundcolor="'rgba(25,118,210, 0.5)'"
            :pointborderwidth="mywidth"
            :pointbordercolor="mypointbordercolor"
            :pointhoverborderwidth="hoverwidth"
            :pointhoverbackgroundcolor="hoverbackgroundcolor"
            :pointhoverbordercolor="hoverbordercolor"
            :bind="true">
          </chartjs-line>
          </div>
      </div>
  </div>
  </div>
</template>

<script>
export default {
  name: 'Chartusage',
  props: {
    userSubmitsProp: {
      type: Array,
      required: true
    }
  },
  data () {
    return {
      submits: this.userSubmitsProp,
      // chart data
      labels: [],
      dataset: [],
      // hover point
      mywidth: 3,
      mypointbordercolor: '#1976D2',
      hoverwidth: 3,
      hoverbackgroundcolor: '#636b6f',
      hoverbordercolor: '#ffd663'
    }
  },
  methods: {
    addChartLabels () {
      debugger
      for (let submit of Object.values(this.submits)) {
        this.labels.push(submit.timestamp)
      }
    },
    addChartdataset () {
      for (let submit of Object.values(this.usersubmits)) {
        this.dataset.push(submit.usage)
      }
    }
  },
  created () {
    this.addChartLabels()
    this.addChartdataset()
  }
}
</script>

<style>
.check-usage {
  margin: 20px 20px 30px 20px;
  box-shadow: 0 4px 70px -18px #707070;
  padding: 10px;
}

.chart {
  padding: 10px;
}
</style>

1 Answer 1

3

So previousSubmits in the Dashboard component is an empty array:

export default {
  name: 'Dashboard',
  data () {
    return {
      currentUserData: {},
      previousSubmits: []
    }
  },

And that's what's getting passed to the chartusage component as userSubmitsProp:

    <chartusage :userSubmitsProp="previousSubmits" />

Which is also referenced as submits in that child component's data:

  data () {
    return {
      submits: this.userSubmitsProp,

And then your code tries to call Object.values on an empty array:

Object.values(this.submits)

BTW, the idiomatic way to provide properties to a component is to use dashes rather than camelCase:

    <chartusage :user-submits-prop="previousSubmits" />
Sign up to request clarification or add additional context in comments.

6 Comments

Thanks for your answer Stephan! But isn't the previousSubmits array filled in with Firestore data in de created cycle of the dashboard component? Or is the previousSubmits array passed to the prop before the created cycle before it is filled in? Thanks for the tip. I will use camelcase for properties from now on :)
Not when the component is created. Only later after the HTTP request promise resolves.
I'm pretty new to this. How can I fix this? Set a timeout so it has time to wait for the data?
I'd suggest spending a little time with some of the Vue tutorials available on the web. The whole approach you've adopted seems contrary to typical Vue development. I think you'll probably be more successful if you stick to more common architectures. There are even several examples (e.g. vuejs.org/v2/examples/firebase.html) on the official Vue web site.
Thanks for your help! I will follow your advise.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.