I am working on a Vue application that uses a lot of charts. As it is now, I am calling the database in each individual chart component, but this means that all the data is called multiple times, which slows down the page. I would like instead to call the database once and then pass the data to each individual chart through props, but I have run into issues with it.
I have an object with data looks like this:
On my main component I get the data from another component that holds the API (called BIService) On this component I also have all my chart components.
<template>
<b-row cols="1" cols-sm="2" cols-lg="4">
<b-col class="mb-4">
<total-empty-units />
</b-col>
<b-col class="mb-4">
<vacancy-rent-loss />
</b-col>
<b-col class="mb-4">
<churn-rate />
</b-col>
<b-col class="mb-4">
<overdue-payments-chart />
</b-col>
</b-row>
</template>
<script>
import axios from '@/config/axios';
import {biService} from '@/services/bi';
import TotalEmptyUnits from '@/components/chart/empty-units/TotalEmptyUnits';
import OverduePaymentsChart from '@/components/chart/overdue-payments/OverduePaymentsChart';
import ChurnRate from '@/components/chart/churn-rate/ChurnRate';
import VacancyRentLoss from '@/components/chart/vacancy-loss/VacancyRentLoss';
export default {
components: {
TotalEmptyUnits,
OverduePaymentsChart,
ChurnRate,
VacancyRentLoss,
},
data: () => ({
bIGraphStats: null,
}),
methods: {
load() {
biService.getBIGraphStatsForCompany()
.then(result => this.bIGraphStats = result.data)
.catch(error => console.error(error));
},
},
};
</script>
Here is an example of what the chart components look like. As you can see, I am calling the database inside the chart as well.
<template>
<b-card class="h-100" @click="showModal = true">
<div class="d-flex">
<h5 class="text-center flex-grow-1">Churn rate</h5>
<b-button variant="link" class="p-0">
<i class="fas fa-external-link-square-alt fa-lg"></i>
</b-button>
</div>
<apexchart
type="radialBar"
height="250"
:chartData="chartData"
:options="options"
:series="series">
</apexchart>
</b-card>
</template>
<script>
import axios from '@/config/axios';
import {biService} from '@/services/bi';
import moment from 'moment';
import VueApexCharts from 'vue-apexcharts'
import Vue from 'vue';
Vue.use(VueApexCharts)
Vue.component('apexchart', VueApexCharts)
export default {
data: () => ({
showModal: false,
chartData: null,
unitGroups: null,
currentMonth: new Date().getMonth(),
series: [],
options: {
chart: {
type: 'radialBar',
offsetY: -20,
sparkline: {
enabled: true
}
},
plotOptions: {
radialBar: {
startAngle: -90,
endAngle: 90,
track: {
background: "#e7e7e7",
strokeWidth: '97%',
margin: 5, // margin is in pixels
dropShadow: {
enabled: true,
top: 2,
left: 0,
color: '#999',
opacity: 1,
blur: 2
}
},
dataLabels: {
formatter: function (val) {
return val;
},
enabled: true,
name: {
show: false
},
value: {
offsetY: -2,
fontSize: '22px',
formatter: function (val) {
return val;
}
}
}
}
},
grid: {
padding: {
top: -10
}
},
fill: {
colors: '#f34860',
},
labels: ['Average Results'],
},
}),
methods: {
currentDateTime() {
return moment().format('MMMM Do YYYY, h:mm:ss a')
}
},
created() {
biService.getBIGraphStatsForCompany()
.then(result => this.series.push(Math.round(result.data.terminatedTenancies)))
.catch(error => console.error(error));
}
}
</script>
So here is what I have tried.
I added a prop to the chart component and called it seriesData, and then I try to pass it into the main component where the database data is fetched. I am using a watcher for this purpose. But nothing is showing up. I am getting the error "Cannot read properties of undefined". on the data I am trying to pass. This is how my new code looks. Can someone guide me to how I might be able to solve this problem?
the main component:
<b-col class="mb-4">
<churn-rate v-if="loaded" :series-data="bIGraphStats" />
</b-col>
The chart component
<template>
<b-card class="h-100" @click="showModal = true">
<div class="d-flex">
<h5 class="text-center flex-grow-1">Churn rate</h5>
<b-button variant="link" class="p-0">
<i class="fas fa-external-link-square-alt fa-lg"></i>
</b-button>
</div>
<apexchart
type="radialBar"
height="250"
:chartData="chartData"
:options="options"
:series="series">
</apexchart>
</b-card>
</template>
<script>
import axios from '@/config/axios';
import {biService} from '@/services/bi';
import moment from 'moment';
import VueApexCharts from 'vue-apexcharts'
import Vue from 'vue';
Vue.use(VueApexCharts)
Vue.component('apexchart', VueApexCharts)
export default {
prop: {
seriesData: Object
},
data: () => ({
showModal: false,
chartData: null,
unitGroups: null,
currentMonth: new Date().getMonth(),
series: [],
options: {
chart: {
type: 'radialBar',
offsetY: -20,
sparkline: {
enabled: true
}
},
plotOptions: {
radialBar: {
startAngle: -90,
endAngle: 90,
track: {
background: "#e7e7e7",
strokeWidth: '97%',
margin: 5, // margin is in pixels
dropShadow: {
enabled: true,
top: 2,
left: 0,
color: '#999',
opacity: 1,
blur: 2
}
},
dataLabels: {
formatter: function (val) {
return val;
},
enabled: true,
name: {
show: false
},
value: {
offsetY: -2,
fontSize: '22px',
formatter: function (val) {
return val;
}
}
}
}
},
grid: {
padding: {
top: -10
}
},
fill: {
colors: '#f34860',
},
labels: ['Average Results'],
},
}),
methods: {
currentDateTime() {
return moment().format('MMMM Do YYYY, h:mm:ss a')
}
},
watch: {
seriesData: {
immediate: true,
handler() {
console.log(this.seriesData)
this.series.push(Math.round(this.seriesData.terminatedTenancies))
}
}
}
}
</script>
