user745587
user745587

Reputation: 125

Chart.js line graph doesn't show up most of the time

I want to display a chart with money donated and the date of the donation. Mysteriously, the chart shows up sometimes (~5% of the time), yet doesn't the other 95% of the time (See pictures at bottom).

I'm very confused about this issue I'm having. I want to create a line chart using some data I'm getting from an API. I'm using chart.js. Sometimes it shows up and sometimes it doesn't. It has nothing to do with getting the API data as (from looking at the console) that is done immediately. So I am sure it is a problem with my way of using Chart.js.

Here is my LineChart.vue:

<script>
import { Line } from 'vue-chartjs'

export default {
  name: 'LineChart',
  extends: Line,
  props: {
    label: {
      type: String
    },
    chartData: {
      type: Array
    },
    options: {
      type: Object
    }
  },
  mounted () {
    const dates = this.chartData.map(d => d.donationDate).reverse()
    const totals = this.chartData.map(d => d.totalMoney).reverse()

    this.renderChart({
      labels: dates,
      datasets: [{
        label: this.label,
        data: totals
      }]
    },
    this.options)
  }
}
</script>

Here is my code for Fundraiser.vue:

<template>
  <div class="container">
    <div class="row mt-5">
      <div class="col">
        <h2>Positive</h2>
        <line-chart :chart-data=recentDonations :options=chartOptions label='Positive'>
        </line-chart>
      </div>
    </div>
  </div>
</template>

<script>
import axios from 'axios'
import moment from 'moment'
import LineChart from '../components/LineChart.vue'

export default {
  name: 'Fundraiser',
  components: { LineChart },
  data () {
    return {
      recentDonations: [],
      chartOptions: {
        responsive: true,
        maintainAspectRatio: false
      }
    }
  },
  async created () {
    const { data } = await axios({
      url: 'http://api.justgiving.com/[MY API KEY]/v1/crowdfunding/pages/[SOME-PAGE]/pledges',
      method: 'get',
      headers: {
        Accept: 'application/json'
      }
    })
    console.log(data)
    data.pledges.forEach(d => { // this part works fine.
      if (d.donationAmount != null) {
        const dateInEpochFormat = d.activityDate.substring(6, 16)
        const donationMade = moment.unix(dateInEpochFormat).format('MM/DD')
        this.recentDonations.push({ donationDate: donationMade, totalMoney: d.donationAmount })
      }
      console.log(this.recentDonations)
    })
  }
}
</script>

As you can see from the pictue below, the data is being pulled fine (array of objects with two properties: donateDate and totalMoney)

enter image description here

So sometimes it shows up (very very rarely): [enter image description here][

Then I refresh the page (without touching ANY code) and all of a sudden: enter image description here

Can someone please help me solve this mystery?

Upvotes: 0

Views: 1221

Answers (1)

Andres Foronda
Andres Foronda

Reputation: 1419

Try to render the graph after receiving the response from the http request, maybe with an if statement and a variable as flag:

<template>
  <div class="container">
    <div class="row mt-5">
      <div class="col" v-if="show">
        <h2>Positive</h2>
        <line-chart
          :chart-data="recentDonations"
          :options="chartOptions"
          label="Positive"
        >
        </line-chart>
      </div>
    </div>
  </div>
</template>

In your export default object, you can have this:

export default {
  name: 'Fundraiser',
  components: { LineChart },
  data () {
    return {
      show: false,
      recentDonations: [],
      chartOptions: {
        responsive: true,
        maintainAspectRatio: false
      }
    }
  },
  async created () {
    const { data } = await axios({
      url: 'http://api.justgiving.com/[MY API KEY]/v1/crowdfunding/pages/[SOME- 
      PAGE]/pledges',
      method: 'get',
      headers: {
        Accept: 'application/json'
      }
    })
    console.log(data)
    data.pledges.forEach(d => { // this part works fine.
      if (d.donationAmount != null) {
        const dateInEpochFormat = d.activityDate.substring(6, 16)
        const donationMade = moment.unix(dateInEpochFormat).format('MM/DD')
        this.recentDonations.push({ donationDate: donationMade, totalMoney: 
        d.donationAmount })
      }
      console.log(this.recentDonations)
    })
    this.show = true;
  }
}

This is a workaround, You are waiting to have the data before render the graph, than way the first time that the graph is rendered, it can use the data and show the information.

The reason to not see data in the graph is because when the graph is rendered there is not information to show, once you get the response from the http request the graph is not updated, to do so, you must to watch the chartData prop, and once chartData is updated, you must call the chart.js update graph method (you can read more about it here: https://www.chartjs.org/docs/latest/developers/updates.html)

A better way to handle the data update is to assign the value to this.recentDonations after the forEach, that way you are not getting updates every time a pledge is pushed: ... const donations = []; data.pledges.forEach(d => { // this part works fine. if (d.donationAmount != null) { const dateInEpochFormat = d.activityDate.substring(6, 16) const donationMade = moment.unix(dateInEpochFormat).format('MM/DD') donations.push({ donationDate: donationMade, totalMoney: d.donationAmount }) } console.log(this.recentDonations) }) this.recentDonation = donations; this.show = true; ...

I did a test with a timeout function using this code (I don't know how to use the justgiving api):

<template>
  <div class="container">
    <div class="row mt-5">
      <div class="col" v-if="show">
        <h2>Positive</h2>
        <line-chart
          :chart-data="recentDonations"
          :options="chartOptions"
          label="Positive"
        >
        </line-chart>
      </div>
    </div>
  </div>
</template>

<script>
import axios from "axios";
import moment from "moment";
import LineChart from "../components/LineChart.vue";

export default {
  name: "Fundraiser",
  components: { LineChart },
  data() {
    return {
      show: false,
      recentDonations: [],
      chartOptions: {
        responsive: true,
        maintainAspectRatio: false
      }
    };
  },
  methods: {
    request() {
      const pledges = [
        { donationDate: "11/08", donationAmount: 5 },
        { donationDate: "11/09", donationAmount: 5 },
        { donationDate: "11/10", donationAmount: 5 },
        { donationDate: "11/11", donationAmount: 5 },
        { donationDate: "11/12", donationAmount: 5 },
        { donationDate: "11/13", donationAmount: 5 },
        { donationDate: "11/14", donationAmount: 5 },
        { donationDate: "11/15", donationAmount: 5 },
        { donationDate: "11/16", donationAmount: 5 },
        { donationDate: "11/17", donationAmount: 5 },
        { donationDate: "11/18", donationAmount: 5 },
        { donationDate: "11/19", donationAmount: 5 },
        { donationDate: "11/20", donationAmount: 5 },
        { donationDate: "11/21", donationAmount: 5 },
        { donationDate: "11/22", donationAmount: 5 }
      ];
      pledges.forEach(d => {
        // this part works fine.
        // if (d.donationAmount != null) {
        // const dateInEpochFormat = d.activityDate.substring(6, 16);
        // const donationMade = moment.unix(dateInEpochFormat).format("MM/DD");
        this.recentDonations.push({
          donationDate: d.donationDate,
          totalMoney: d.donationAmount
        });
        // }
        console.log(this.recentDonations);
      });
      this.show = true;
    }
  },
  async created() {
    await setTimeout(this.request, 1000);
  }
};
</script>

If you remove the if statement, the graph doesn't show any data

Upvotes: 1

Related Questions