2

I am new to Vuejs and i wanna know how to fetch data from my API to display chart.

Below is my code, where i have used data as "date and challenge" and have fed data directly to it, but now i want to call my API and feed the data from it to "date and challenge".

Code that i have used it to display chart without API:

<template>
  <canvas id="mychart" width="550" height="300"></canvas>
</template>

<script>

export default {
  name: 'Chart',
  data: () => ({
    date: [
      1600934100.0,
      1602009600.0,
      1602747060.0,
      1603050158.390939,
      1603305573.992575
    ],
    challenge: [
      9.0,
      9.5,
      2.5,
      11.52,
      12.4
    ]
  }),
  mounted () {
    // eslint-disable-next-line no-unused-vars
    const data = this.date.map((date, index) => ({
      x: new Date(date * 1000),
      y: this.challenge[index]
    }))

    const ctx = document.getElementById('mychart').getContext('2d')
    // eslint-disable-next-line no-undef,no-unused-vars
    const Chart_2 = new Chart(ctx, {
      type: 'line',
      data: {
        datasets: [
          {
            data,
            label: 'Chart from API ',
            borderColor: '#7367F0'
          }
        ]
      },
      options: {
        scales: {
          xAxes: [
            {
              type: 'time',
              time: {
                unit: 'month',
                displayFormats: {
                  month: 'MMM YYYY'
                }
              }
            }
          ],
          yAxes: [
            {
              ticks: {
                // eslint-disable-next-line no-unused-vars
                callback (value, index, values) {
                  return `${value  }%`
                }
              }
            }
          ]
        }
      }
    })
  }
}
</script>

I know to get API we use 'axios' or 'fetch' , so whenever i get API and just do console.log(response.data) i will get my data in the console in my browser, but further i dont know to map it and use those data to feed "date and chalenge" in order to display chart.

Here is my API:

My API which contains data in it: https://api.wirespec.dev/wirespec/stackoverflow/fetchchartdataforvuejs

Please someone help me to display chart by using my API in my code.

1

3 Answers 3

2

have you tried like this one?

solution 1

Add async/await so it will wait until the data get populated to data and challege.

async mounted () {
    let result = await axios.get('https://api.wirespec.dev/wirespec/stackoverflow/fetchchartdataforvuejs')
    this.date = result.data.date
    this.challenge = result.data.challenge

    // eslint-disable-next-line no-unused-vars
    const data = this.date.map((date, index) => ({
      x: new Date(date * 1000),
      y: this.challenge[index]
    }))

    const ctx = document.getElementById('mychart').getContext('2d')
    // eslint-disable-next-line no-undef,no-unused-vars
    const Chart_2 = new Chart(ctx, {
      type: 'line',
      data: {
        datasets: [
          {
            data,
            label: 'Chart from API ',
            borderColor: '#7367F0'
          }
        ]
      },
      options: {
        scales: {
          xAxes: [
            {
              type: 'time',
              time: {
                unit: 'month',
                displayFormats: {
                  month: 'MMM YYYY'
                }
              }
            }
          ],
          yAxes: [
            {
              ticks: {
                // eslint-disable-next-line no-unused-vars
                callback (value, index, values) {
                  return `${value  }%`
                }
              }
            }
          ]
        }
      }
    })
  }

or in another way, you can fetch the data from API in other component and send date and challege as props to this component.

solution 2

I assume you have chart component chart.vue

chart.vue

<template>
  <canvas id="mychart" width="550" height="300"></canvas>
</template>

<script>

export default {
  name: 'Chart',

  props: ['date', 'challenge],

  data: () => ({

  }),
  mounted () {
    // eslint-disable-next-line no-unused-vars
    const data = this.date.map((date, index) => ({
      x: new Date(date * 1000),
      y: this.challenge[index]
    }))

    const ctx = document.getElementById('mychart').getContext('2d')
    // eslint-disable-next-line no-undef,no-unused-vars
    const Chart_2 = new Chart(ctx, {
      type: 'line',
      data: {
        datasets: [
          {
            data,
            label: 'Chart from API ',
            borderColor: '#7367F0'
          }
        ]
      },
      options: {
        scales: {
          xAxes: [
            {
              type: 'time',
              time: {
                unit: 'month',
                displayFormats: {
                  month: 'MMM YYYY'
                }
              }
            }
          ],
          yAxes: [
            {
              ticks: {
                // eslint-disable-next-line no-unused-vars
                callback (value, index, values) {
                  return `${value  }%`
                }
              }
            }
          ]
        }
      }
    })
  }
}
</script>

and in other component, import your chart.vue

<template>
    <div>
        <Chart v-if="!isLoading" :date="date" :challenge="challenge" />
    </div>
</template>

<script type="text/javascript">
    import Chart from 'PATH TO chart.vue'
    export default {
        components: {
            Chart
        },
        data () => ({
            date: [],
            challenge: [],
            isLoading: false
        }),
        methods: {
            async getData () {
                this.isLoading = true
                let result = await axios.get(API URL)
                this.date = result.data.date
                this.challenge = result.data.challenge
                this.isLoading = false
            }
        },
        mounted () {
            this.getData()
        }
    }
</script>

In chart.vue, delete date and challege from data because you will have props, for the best practice props and data cannot have same property name.

In other component where chart.vue get imported, just fetch the data as usual.

Things I did when I was using chartjs for my project, I always add v-if in , it will let the axios fetch the data first and then re-mount the chart component. Because I guess chartjs is not reactive on vuejs data changes, so will need to update the data first then re-mount again.

Sign up to request clarification or add additional context in comments.

8 Comments

Thank you for your answer, i had tried this earlier also, but even this is not working, if i do like this i get error as vue.runtime.esm.js?2b0e:619 [Vue warn]: Error in mounted hook (Promise/async): "TypeError: Cannot read property '0' of undefined". Please can you tell is there any other way that i can display my chart from API. And can you also tell me what should be given in data () => ({ date: '?' challenge: '?' )} because in datasets i have specified it has 'data'
make sure you didnt get cors problems, I tried it on codesandbox and got cors error
I tried 2nd solution, but nothing was displayed in chart, and there is no error in console also, don't know what i should do now, i have been trying different ways to solve it, but not able to display the chart from API
please check my codesandbox codesandbox.io/s/friendly-leakey-e7pip?file=/src/components/… . because I got cors problems, assume add data is calling an API. overal it should work with API
|
0

Finally, I got the answer Hoorah!

I am sharing, how I did it even you can do the same in order to visualize chart with your API data.

<template>
  <div class="chart-container" style="position: relative; height: 25vh; width:100%;">
    <canvas id="DisplayChart" ></canvas>
  </div>
</template>

<script>
import moment from 'moment'
export default {
  name: 'Chart_from_API',
  data () {
    return {
      myChart: []
    }
  },
  async mounted () {
    await this.$http.get('https://api.wirespec.dev/wirespec/stackoverflow/fetchchartdataforvuejs') //Your API has to be given here
      .then((response) => {
        const result = response.data
        const ctx = document.getElementById('DisplayChart').getContext('2d')
        const Chart_data = []
        for (let i = 0; i < result.date.length; i++) {
          Chart_data.push({
            x_axis: moment(result.date[i], 'X').toDate(),  //To Convert Unix Timestamp into Date
            y_axis: result.challenge[i]
          })
        }
        // eslint-disable-next-line init-declarations,prefer-const
        let myChart
        if (myChart !== undefined) {
          myChart.destroy()
        }

        // eslint-disable-next-line no-undef
        myChart = new Chart(ctx, {
          type: 'line',
          data: {
            datasets: [
              {
                label: 'Chart_from_API',
                data: Chart_data,
                borderColor: '#EA5455',
                lineTension: 0
              }
            ]
          },
          options: {
            lineTension: 0,
            maintainAspectRatio: false,
            legend: {
              display: false
            },
            scales: {
              yAxes: [
                {
                  scaleLabel: {
                    display: false
                  },
                  ticks: {
                    beginAtZero: true,
                    // eslint-disable-next-line no-unused-vars
                    callback (value) {
                      return `${value  }k`    // y-axis value will append k to it
                    }
                  }
                }
              ],
              xAxes: [
                {
                  type: 'time',
                  time: {
                    unit: 'month'
                  },
                  scaleLabel: {
                    display: true,
                    labelString: ''
                  }
                }
              ]
            }
          }
        })
      })
      .catch((error) => {
        console.log(error)
      })
  }
}
</script>

Comments

0

You can use the vue-chartjs which is a wrapper for Chart.js in Vue.

Install it over the npm package manager.

npm install vue-chartjs chart.js

According to the documentation, there is a common problem when accessing the data from an asynchronous API endpoint:

The problem with this approach is that Chart.js tries to render your chart and access the chart data synchronously, so your chart mounts before the API data arrives.

To prevent this, a simple v-if is the best solution. The following Vue component utilizes a boolean variable to stop the chart mounting before the data arrives.

<template>
  <div>
    <h1>Stock Data</h1>
    <!-- The v-if is used to conditionally render a block -->
    <Bar id="my-chart-id" v-if="loaded" :options="chartOptions" :data="chartData" :width="600" />
  </div>
</template>

<script>
import { Bar } from 'vue-chartjs'
import { Chart as ChartJS, Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale } from 'chart.js'

ChartJS.register(Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale)

export default {
  name: 'BarChart',
  components: { Bar },
  data: () => ({
    // Prevents chart to mount before the API data arrives
    loaded: false,
    chartData: {
      labels: [],
      datasets: [
        {
          label: 'My Label',
          data: [],
          backgroundColor: 'rgba(54, 162, 235, 0.2)'
        }
      ]
    },
    chartOptions: {
      responsive: true
    }
  }),
  async mounted() {
    const apiUrl = 'http://localhost:8000/data'

    // Make an HTTP request to fetch the data from the API endpoint
    await fetch(apiUrl)
      .then((response) => response.json())
      .then((data) => {
        // Extract data from the API response and update the chartData
        this.chartData.labels = data.map((stock) => stock.date)
        this.chartData.datasets[0].data = data.map((stock) => stock.value)

        // Allow the chart to display the data from the API endpoint
        this.loaded = true
      })
      .catch((error) => {
        console.error('Error fetching data:', error)
      })
  }
}
</script>

The key is to render the bar chart only if the data is arrived successfully. It is achieved by setting the loaded variable to true. Note that, you need to reload the page whenever new data is arrived.

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.