admin管理员组

文章数量:1122846

I am trying to use response data from my api call to populate a Pie Chart from Chart.js. The issue is that the UI does not update after the response data is assigned to the chartData object.

These are the console logs:

Api data:

Object { recycling: 123, general: 54, organic: 39 }

Response Data:

{
  "chartData": {
    "recycling": 123,
    "general": 54,
    "organic": 39
  }
}

Processed Chart Data:

Proxy { <target>: (3) […], <handler>: {…} }
​
<target>: Array(3) [ 123, 54, 39 ]
​
<handler>: Object { _isReadonly: false, _isShallow: false }
<!-- PieChart.vue -->

<script setup>
import {onMounted, ref} from 'vue';
import { Pie } from 'vue-chartjs';
import { Chart as ChartJS, Title, Tooltip, Legend, ArcElement } from 'chart.js';
import axios from "axios";
// Register necessary Chart.js components
ChartJS.register(Title, Tooltip, Legend, ArcElement);

const chartData = ref({
  labels: ['Recycling', 'General Waste', 'Organic Waste'],
  datasets: [
    {
      label: 'Waste Distribution',
      backgroundColor: ['#0C2A77', '#585858', '#36BA24'],
      data: [0, 0, 0], // set initial data to 0
    },
  ],
});

const chartOptions = ref({
  responsive: true,
  plugins: {
    legend: {
      display: true,
      position: 'top',
    },
    title: {
      display: true,
      text: 'Total Waste Distribution',
    },
  },
});

onMounted(async() => {
  
  const user_id = JSON.parse(sessionStorage.getItem('user_id'));
  if(user_id){
    try {
      const response = await axios.get(`http://localhost/CI4-EcoTrack/public/totalData/${user_id}`,
          { headers: { "Content-Type": "application/json" } }
      );
      console.log("Response Data:", JSON.stringify(response.data, null, 2));

      const apiData = response.data.chartData;

      console.log("Recycling data: ", apiData.recycling)
      chartData.value.datasets[0].data = [
        apiData.recycling || 0,
        apiData.general || 0,
        apiDataanic || 0,
      ];

      console.log("Api data: ",apiData);
      console.log("Processed Chart Data: ", chartData.value.datasets[0].data);

    } catch (e) {
      console.error("Error fetching data:", e.response ? e.response.data : e);
    }
  }

})

</script>
<template>
  <div class="chart-container">
    <Pie :data="chartData" :options="chartOptions" />
  </div>
</template>

<style scoped>
.chart-container {
  width: 20em;
  height: 20em;
  margin: auto;
}
</style>

I believe the issue lies with either how I am trying to update the chart.

I have tried defining the chart as a ref, then calling the update() function.

I am trying to use response data from my api call to populate a Pie Chart from Chart.js. The issue is that the UI does not update after the response data is assigned to the chartData object.

These are the console logs:

Api data:

Object { recycling: 123, general: 54, organic: 39 }

Response Data:

{
  "chartData": {
    "recycling": 123,
    "general": 54,
    "organic": 39
  }
}

Processed Chart Data:

Proxy { <target>: (3) […], <handler>: {…} }
​
<target>: Array(3) [ 123, 54, 39 ]
​
<handler>: Object { _isReadonly: false, _isShallow: false }
<!-- PieChart.vue -->

<script setup>
import {onMounted, ref} from 'vue';
import { Pie } from 'vue-chartjs';
import { Chart as ChartJS, Title, Tooltip, Legend, ArcElement } from 'chart.js';
import axios from "axios";
// Register necessary Chart.js components
ChartJS.register(Title, Tooltip, Legend, ArcElement);

const chartData = ref({
  labels: ['Recycling', 'General Waste', 'Organic Waste'],
  datasets: [
    {
      label: 'Waste Distribution',
      backgroundColor: ['#0C2A77', '#585858', '#36BA24'],
      data: [0, 0, 0], // set initial data to 0
    },
  ],
});

const chartOptions = ref({
  responsive: true,
  plugins: {
    legend: {
      display: true,
      position: 'top',
    },
    title: {
      display: true,
      text: 'Total Waste Distribution',
    },
  },
});

onMounted(async() => {
  
  const user_id = JSON.parse(sessionStorage.getItem('user_id'));
  if(user_id){
    try {
      const response = await axios.get(`http://localhost/CI4-EcoTrack/public/totalData/${user_id}`,
          { headers: { "Content-Type": "application/json" } }
      );
      console.log("Response Data:", JSON.stringify(response.data, null, 2));

      const apiData = response.data.chartData;

      console.log("Recycling data: ", apiData.recycling)
      chartData.value.datasets[0].data = [
        apiData.recycling || 0,
        apiData.general || 0,
        apiData.organic || 0,
      ];

      console.log("Api data: ",apiData);
      console.log("Processed Chart Data: ", chartData.value.datasets[0].data);

    } catch (e) {
      console.error("Error fetching data:", e.response ? e.response.data : e);
    }
  }

})

</script>
<template>
  <div class="chart-container">
    <Pie :data="chartData" :options="chartOptions" />
  </div>
</template>

<style scoped>
.chart-container {
  width: 20em;
  height: 20em;
  margin: auto;
}
</style>

I believe the issue lies with either how I am trying to update the chart.

I have tried defining the chart as a ref, then calling the update() function.

Share Improve this question asked Nov 22, 2024 at 14:56 Gary O'ConnorGary O'Connor 11
Add a comment  | 

1 Answer 1

Reset to default 0

The attempt to update the chart does not conform to the method detailed in the vue-chartjs documentation. The proper way to update the chart is for chartData to be a computed property, where the data is a dependency that, when updated, will cause the computed property to reevaluate and reactively update the chart in the UI.

With chartData as a computed, you can have the dataset data value be it's own ref, that you update using the API data. This update should then trigger the computed to reevaluate.

const wasteData = ref([0, 0, 0]) // set initial data to 0
const chartData = computed(() => {
  return {
    labels: ['Recycling', 'General Waste', 'Organic Waste'],
    datasets: [
      {
        label: 'Waste Distribution',
        backgroundColor: ['#0C2A77', '#585858', '#36BA24'],
        data: wasteData.value
      }
    ]
  }
})

onMounted(async () => {
  ...
  wasteData.value = [
    apiData.recycling || 0,
    apiData.general || 0,
    apiData.organic || 0
  ]
  ...
})

Alternatively

Not being a deeply reactive object, chartData does not cause a reactive update when changing nested data. You can keep most of the code the same as you have now but just add a deep copy of the entire object. This should trigger a reactive update of the UI.

chartData.value.datasets[0].data = [
  apiData.recycling || 0,
  apiData.general || 0,
  apiData.organic || 0
]
chartData.value = JSON.parse(JSON.stringify(chartData.value)) // deep copy

本文标签: javascriptUsing JSON data from an api call to reactively update a chartStack Overflow