Search code examples
vue.jschart.jsvuexvue-chartjs

How to populate a chart with data coming from API?


I use vue-chart.js along with Vue2 to create a chart. I have a problem with passing API data to a chart. I use Vuex store where I fetch data from API. There's a poor example on vue-chartjs.org showing how to handle an API. I also checked SO looking for an answer but in most cases renderChart() placed in mounted() is used, don't know if it's some workaround or proper way of dealing with this problem. I know that I need to pass Object instead of Array. I pass state directly to data , here :data="allSales". This is my problematic code which throws errors:

Invalid prop: type check failed for prop "data". Expected Object, got Array

Error in mounted hook: "TypeError: Cannot read properties of undefined (reading 'map')"

<template>
  <v-container>
    <v-row>
      <v-col cols="6">
        <Bar v-if="loaded"
          id="my-chart-id"
          :options="chartOptions"
          :data="allSales"/>
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
import { mapActions, mapState } from 'vuex';
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 {

    components: {
      Bar
    },

    data() {
      return {
      chartOptions: {
        responsive: true
      },
      loaded: false
      }
    },

    computed: {
      ...mapState('custom', ['allSales'])
    },

    methods: {
      ...mapActions('custom', ['getAllSalesAction']),
    },

    mounted() {   
      
      this.loaded = false
      try {
        this.getAllSalesAction()
        this.loaded = true
      } catch (e) {
        console.error(e)
      }
    },

  }
</script>

EDIT: I add my Vuex store:

import axios from "axios";


const state = {
    allSales: [],
};

const mutations = {
    getAllSales: (state, all) => state.allSales = all, 

};

const actions = {
    async getAllSalesAction({commit})
    {       
        const response = await axios.get(`https://localhost:44327/api/Commission/allData`)
        commit('getAllSales', response.data)
    },
};

export default {
    namespaced: true,
    state,
    mutations,
    actions,
};

Basically I have 2 questions:

  1. How properly populate chart with API data (using Vuex in my case)?
  2. How can I choose specific column names from API and pass to a chart? Say I have 20 columns and just wanted to show 3 of them on a chart?

Solution

  • Read carefully the documentation and notice how the data prop of the Bar component is of type Object while you are feeding it with Array.

    Follow the example from the documentation and use a Vuex getter instead of directly reading the state in order to generate the right data format:

    const getters = {
      getAllSales(state)
      {
        return {
          labels: [ 'January', 'February', 'March'],
          datasets: [
            {
              label: 'Data One',
              backgroundColor: '#F87979',
              data: state.allSales,
            }
          ]
        };
      },
    };