I am building a dashboard using Vue.js 3 and ApexCharts with the composition API. The data for the charts is held in a Pinia data store.
I have a function that pulls data from a sample .json file (which models what an API will return once it is set up), processes, and returns the data as a multidimensional array for the charts that is stored in the Pinia store.
The problem I’m having is when I run the function to update the data, I can see it update in the Pinia store via vue devtools, but the chart does not change to reflect the new values like the rest of the app does.
At the advice of other stack overflow answers, I’ve wrapped chart options and series in ref(). I’ve also read this post on GitHub, but as I’m fairly new to Vue and have only worked with the composition API, I’m unsure what exactly to implement in my code to make the charts reactive to Pinia data.
I have created a sample repo with a single chart and sample data on stackblitz showing the behavior I’m experiencing.
Chart options and series code:
let chartOptions = ref({
chart: {
id: "grocerChart",
type: "bar",
stacked: true,
stackType: "100%",
toolbar: {
show: true,
tools: {
download: true,
zoom: false,
zoomin: true,
zoomout: true,
reset: true,
},
},
},
title: {
text: storeData.selectedRegion,
align: "center",
},
plotOptions: {
bar: {
horizontal: true,
},
},
grid: {
padding: {
bottom: 20,
right: 20,
top: 5,
},
},
xaxis: {
categories: storeData.chartData[0], // ['Fruit', "Meat", "Vegetables"],
tickPlacement: "on",
labels: {
rotate: 0,
style: {
fontSize: 10,
},
},
},
fill: {
opacity: 1,
},
legend: {
fontSize: 10,
offsetX: 0,
offsetY: 0,
},
dataLabels: {
enabled: false,
},
noData: {
text: "No Data",
style: {
fontSize: "24px",
},
},
});
let chartSeries = ref([
{
name: storeData.chartData[1][0][0], // 'fruit',
data: storeData.chartData[1][0][1], // [10, 14, 10]
},
{
name: storeData.chartData[1][1][0], // 'meat',
data: storeData.chartData[1][1][1], // [10, 10, 4]
},
{
name: storeData.chartData[1][2][0], // 'vegetable',
data: storeData.chartData[1][2][1], // [9, 7, 12]
},
]);
Pinia code:
import {ref} from 'vue'
import {defineStore} from 'pinia'
export const useDataStore = defineStore('data', () => {
let selectedRegion = ref('No Region Selected');
let chartData = ref([
[],
[
[[], []],
[[], []],
[[], []]
]
]);
return {
selectedRegion,
chartData
}
})
Function to process model .json data and return multidimensional array for chart:
function updateData(data, selectedRegion) {
// Filter data by selected state
const selStateData = data.filter(item => item.state === selectedRegion);
// Extract and sort store names
const stores = [...new Set(selStateData.map(item => item.store))].sort();
// Extract and sort category values
const categories = [...new Set(selStateData.map(item => item.category))].sort();
// Initialize the result array for categorized data
const categorizedData = categories.map(category => [category, Array(stores.length).fill(0)]);
// Populate the categorized data
selStateData.forEach(item => {
const storeIndex = stores.indexOf(item.store);
const categoryIndex = categories.indexOf(item.category);
categorizedData[categoryIndex][1][storeIndex] += item.inventory;
});
return [stores, categorizedData];
}
Button to place the above data into Pinia store:
<v-btn
class="ma-3"
@click="storeData.chartData = updateData(grocerData, storeData.selectedRegion)"
>
Update
</v-btn>
Any help is greatly appreciated!