Reputation: 1182
This is my chartjs component and I'm trying to pass two arrays from the backend. Somehow Vue.js gets the arrays within Vue and yet it doesn't display anything. I'm very new to Vue so bear with me.
Chartjs.vue
<template>
<div class="main-content">
<div class="page-header">
<h3 class="page-title">Chart JS</h3>
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="#">Home</a></li>
<li class="breadcrumb-item"><a href="#">Charts</a></li>
<li class="breadcrumb-item active">Chart JS</li>
</ol>
</div>
<div class="row">
<div class="col-sm-12">
<div class="card">
<div class="card-header">
<h6>Chartjs</h6>
</div>
<div class="card-body">
<div class="mb-4">
<h5 class="section-semi-title">
Line Chart
</h5>
<line-chart
:labels='["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"]'
:values='values'
/>
</div>
<div class="mb-4">
<h5 class="section-semi-title">
Bar Chart
</h5>
<bar-line-chart
:labels='["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"]'
:values='values'
:valuesline='valuesline'
/>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script type="text/babel">
import LineChart from '../../../components/chartjs/LineChart.vue'
import BarChart from '../../../components/chartjs/BarChart.vue'
import BarLineChart from '../../../components/chartjs/BarLineChart.vue'
import PieChart from '../../../components/chartjs/PieChart.vue'
import DoughnutChart from '../../../components/chartjs/DoughnutGraph.vue'
export default {
components: {
LineChart,
BarChart,
BarLineChart,
PieChart,
DoughnutChart,
values:[],
valuesline:[]
},
methods: {
async fetchBarChartData ({ anio, sort }) {
await axios.get(`/api/ingresos-por-mes/${anio}`).then(res=>{
this.values=res.data.qty;
this.valuesline=res.data.perc;
});
}
},
mounted() {
this.fetchBarChartData({anio:2018});
},
data () {
return {
pieAndDoughtnut: {
labels: ['Red', 'Blue', 'Yellow'],
data: [300, 50, 100],
bgColors: [
'#FF6384',
'#36A2EB',
'#FFCE56'
],
hoverBgColors: [
'#FF6384',
'#36A2EB',
'#FFCE56'
]
},
values: this.values,
valuesline: this.valuesline
}
}
}
</script>
BarLineChart.vue
<template>
<div class="graph-container">
<canvas id="graph" ref="graph"/>
</div>
</template>
<script>
import Chart from 'chart.js'
export default {
props: {
labels: {
type: Array,
require: true,
default: Array
},
values: {
type: Array,
require: true,
default: Array
},
valuesline: {
type: Array,
require: true,
default: Array
}
},
mounted () {
let context = this.$refs.graph.getContext('2d')
let options = {
responsive: true,
maintainAspectRatio: false,
legend: {
display: false
}
}
let data = {
labels: this.labels,
datasets: [
{
label: 'My First dataset',
backgroundColor: 'rgba(79, 196, 127,0.2)',
borderColor: 'rgba(79, 196, 127,1)',
borderWidth: 1,
hoverBackgroundColor: 'rgba(79, 196, 127,0.4)',
hoverBorderColor: 'rgba(79, 196, 127,1)',
data: this.values
},
{
label: 'My First dataset',
data: this.valuesline,
type: 'line'
}
]
}
this.myBarChart = new Chart(context, {
type: 'bar',
data: data,
options: options
})
},
beforeDestroy () {
this.myBarChart.destroy()
}
}
</script>
<style scoped>
.graph-container {
height: 300px;
}
</style>
What's odd is that if I make a mistake passing the arguments to the lower components. For example:
<line-chart
:labels='["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"]'
:values='values.data'
/>
Adding ".data" to values breaks that component but lets the other components load the chart below.
Is there anyone who had to deal with this in the past? I'm using a dashboard I found on laraspace.in just in case.
EDIT: I've added this to the codesandbox so you can help me more easily.
https://codesandbox.io/embed/vue-template-x4z7b
EDIT 2: Managed to make it work with local values in the sandbox but somehow it doesn't work in local when calling the api instead.
Upvotes: 1
Views: 1964
Reputation: 3991
I apologize: vuejs documentation on how to fetch async data and integrate it into you application is not the best. I wish they would be more opinionated on best practices here with more examples.
While your async api call is being made, this.values
is an empty array (this.values.data
doesn’t exist until the api call responds). Before the data comes back, vue creates the child component which creates a chart in it using the empty values array, resulting in a blank chart. You must wait until the data is loaded to create the child component (and hence the chart). So how do we do that?
this.loaded = true
, and use a v-if="loaded"
on any child components that depend on that data, see: https://v2.vuejs.org/v2/guide/conditional.htmlHere is a working code sandbox with a dummy api call replicating your changes: https://codesandbox.io/s/vue-template-4b3lm
All of the changes were made to the Chartjs.vue file.
v-if
: to re-render the chart inside the component (instead of delaying the whole component with v-if) when the data comes in (any time the props change).Upvotes: 1