Troubleshooting the compatibility between chart.js and vue.js

Implementing chart.js with vue has been successful so far, but I encountered an issue when fetching chart data via axios. The chart does not display anything because the data is not available when the chart component is mounted. I am looking for a solution to dynamically rerender the charts once the data in my component is loaded instead of waiting for the Ajax call to finish...

I pass all the necessary data for my chart through props to the chart component:

<template>
<section class="CHARTmaincontainer">
    <canvas :id="id" :width="width" :height="height"></canvas>
</section>
</template>
<!--SCRIPTS-->
<script>
import Chart from 'chart.js';
export default {
name: 'ChartJS',


props:
{
    id:{ required:true, type:String },
    type:{ default:'bar', type:String },
    width:{ default:400, type:Number},
    height:{ default:175, type:Number },
    data:{ required:true, type:Array },
    label:{ default:'Gráfico', type:String },
    labels:{ required: true, type:Array } 
},


mounted()
{
    let ctx = document.getElementById(this.id);
    let chart = new Chart(ctx, {
    type: this.type,
    data: {
        labels: this.labels,
        datasets: [{
            label: this.label,
            data: this.data,
            backgroundColor: [
                'rgba(255, 99, 132, 0.2)',
                'rgba(54, 162, 235, 0.2)',
                'rgba(255, 206, 86, 0.2)',
                'rgba(75, 192, 192, 0.2)',
                'rgba(153, 102, 255, 0.2)',
                'rgba(255, 159, 64, 0.2)'
            ],
            borderColor: [
                'rgba(255, 99, 132, 1)',
                'rgba(54, 162, 235, 1)',
                'rgba(255, 206, 86, 1)',
                'rgba(75, 192, 192, 1)',
                'rgba(153, 102, 255, 1)',
                'rgba(255, 159, 64, 1)'
            ],
            borderWidth: 1
        }]
    },
    options: {
        scales: {
            yAxes: [{
                ticks: {
                    beginAtZero: true
                },
                gridLines: {
                    display: true
                }
            }],
            xAxes: [{
                ticks: {
                    beginAtZero: true
                },
                gridLines: {
                    display: true
                }
            }]
        },
    },
    legend: {
        display: false
    },
    tooltips: {
        enabled: true,
        mode: 'single',
        callbacks: {
            label: function(tooltipItems, data) {
                return '$' + tooltipItems.yLabel;
            }
        }
    },
    responsive: true,
    maintainAspectRatio: false,
    });
},
};
</script>
<!--STYLES-->
<style scoped>
.CHARTmaincontainer{width:100%; display:flex; flex-direction:column; height:auto; margin:20px 0px;}
</style>

Below is the component where I include my chart components and provide the data:

<template>
<section class="entry_maincontainer">
    <chart-js v-if="ordersCount"
        :id="'grafico1'"
        :data="ordersCount"
        :label="'Descuentos vendidos'"
        :labels="['Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Ago', 'Oct', 'Nov', 'Dic']">
    </chart-js>
</section>
</template>
<!--SCRIPTS-->
<script>
import { mapState, mapGetters, mapActions, mapMutations } from 'vuex';
export default {
name: 'StatsPanel',


computed:
{
    ...mapState('Orders', ['orders']),
    ...mapGetters('Orders', ['ordersCount', 'ordersTotal']),
    ...mapState('Globals', ['globals']),
    ...mapState('Loader', ['loader']),
},


mounted()
{
    console.log(this.$options.name+' component successfully mounted');
    this.getAll();
},


methods:
{
    ...mapActions('Orders', ['getAll']),
    ...mapMutations('Loader', ['RESET_LOADER']),
}


};
</script>
<!--STYLES-->
<style scoped>
</style>

The main data prop used to render the chart is the following getter:

ordersCount: state => {

        let monthlyCount = { Enero:0, Febrero:0, Marzo:0, Abril:0, Mayo:0, Junio:0, Julio:0, Agosto:0, Septiembre:0, Octubre:0, Noviembre:0, Diciembre:0 };

        _.forEach(state.orders,  function(order) { 
            let capitalizedMonth = _.upperFirst(Vue.moment(order.created_at).format('MMMM'));
            monthlyCount[capitalizedMonth] = parseInt( monthlyCount[capitalizedMonth] ) + parseInt( order.discountcodes.length );
        });

        let values = Object.values(monthlyCount);

        return values;
    },

Answer №1

If you need to update a chart, Chart.js offers the update method that should be called after making changes to the data of the chart instance. For more information, refer to the section on Updating Charts.

To achieve this, you can initialize a chart instance in the mounted hook as usual and then set up a watcher to monitor your props and trigger an update of the chart instance accordingly:

this.chart = new Chart(this.$refs.canvas, {
  type,
  data,
  options
});

this.$watch(
  vm => (vm.data, vm.options),
  () => {
    this.chart.data = this.data;
    this.chart.options = this.data;
    this.chart.update();
  }
);

For a demonstration, check out this Live Example.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Access SCSS variable values in Angular HTML or TypeScript files

So, I've been looking into whether it's feasible to utilize the SCSS variable value within HTML or TS in Angular. For instance: Let's say I have a variable called $mdBreakpoint: 992px; stored inside the _variable.scss file. In my HTML cod ...

Distinguish between Arrays and Objects in JavaScript

My AJAX request is fetching a JSON formatted response which could be in the form of an object like this: { name: "gideon", class: "knight", ... } or an array of objects like this: [ { name: "gideon", class: "knight", ...

Exploring JSON parsing using javascript?

I'm currently attempting to work through this webRTC example and have encountered an issue that appears to be minor in nature... The if statement consistently fails to return true, despite the fact that the console message indicates that the property ...

Sending arguments from an NPM script to a NodeJS script

In my main script (publish-all.js), I am trying to call the npm publish script of an Angular project. This Angular project also has a sub-script (publish.js) that performs various tasks (creating folders, copying files, moving folders...) after running ng ...

Tips for transferring a data table (an object) from a JavaScript file to Node.js

On my HTML page, there is a table displaying student names and information, along with controls to manage the table. I created a save button to save this table as an object named SIT in my JavaScript code. I was able to manually save this table in MongoDB ...

What are the solutions for addressing the issue of being unable to update the React state on a component that is unmounted?

I encountered an issue with my code and I need some assistance. Below is the code snippet from App.tsx function App() { const dispatch = useDispatch(); const auth = useSelector((state: RootStateOrAny) => state.auth); const token = useSelector( ...

Swipe JS: tap on the edge to view the next item

Currently utilizing Swipe JS to generate a full-screen image gallery and aiming to incorporate the functionality of clicking on the left or right edge to navigate between the previous and next slides. An attempt was made to create absolutely positioned a ...

Can you provide the function that updates subscription and account details using Recurly JS?

Recurly has unfortunately declined to provide assistance with this issue. I must understand the specific format of the objects, as Recurly will not process any extra data or incorrect query arguments (which vary for each function). Ruby: subscription = ...

Capture a screenshot of the icons

I'm curious about displaying specific parts of images in a React Native application. class InstaClone extends Component { render() { return( <View style={{ flex:1, width:100 + "%", height:100 + "%" }}> <View style={st ...

In Vue, you can dynamically load a JavaScript file containing a JavaScript object during runtime

I'm in the process of developing a no-code application with Vue. I have come across an issue where I cannot add functions to a JSON file that I want to import at runtime. As a workaround, I decided to use a JavaScript or TypeScript file to store the J ...

Find items that were recently added in the past three days using TypeScript

Looking for a way to filter an object array of products where each element has a string property called addedDate. The goal is to only include products that were added within the last 3 days. let now = new Date(); let latestProducts: IProduct[]; latest ...

Binding Form Inputs in VueJS

Hello, I am new to Vue and I have come across an issue while using the foreach loop: Problem: Whenever I click on any checkbox, all checkboxes get selected. create.blade.php @foreach ($permissions as $permission) <li class="list-grou ...

Should the hourly charge schedule be based on user input and be created from scratch or utilize existing templates?

I have hit a roadblock while creating a charging schedule based on user input for my project. I am debating whether to search for and modify an existing plugin or develop it from scratch. The schedule involves solar charging electric cars between 7am and ...

Dispatch an angular POST Request

I am facing an issue where Angular is sending a GET request instead of a POST request when I want to send a post request. The code for my Angular request is as follows: $http({ method: 'POST', url: pages_url, params: { ...

Unable to establish headers

I am experiencing a console error in a route with basic authentication implemented. Error: Can't set headers after they are sent. at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:356:11) at ServerResponse.header This error only ...

Using external HTML content in react components

I've been working on a website and I'm trying to embed external HTML onto my page. I attempted using iframe, but all it shows is a blank page with no content. import React from 'react'; function MapVisualization(props) { return( ...

What is the best way to close a dropdown when clicking away from it on the body?

I wish for the dropdown menu to lose its "show" class when clicked anywhere in the body or window, even if it already has the class "dropdown.menu.show". The show class gets removed and added before utilizing the code `(window.onclick = function(event){})` ...

ESLint throws an error when the watch method in Vue is used with the immediate option

My Vue code includes a Watch method with immediate: true watch: { currentQuestion() { // console.log("Watch currentQuestion", "Start"); immediate: true; this.selectedIndex = null; this.shuffleAnswers(); } } Upon running ...

The browser is struggling to interpret the incorrect HTML content

I am looking for a way to create a function that can retrieve account data from my database and organize it in a user-friendly HTML table where users can make selections and modifications. The code I have so far is as follows: $.ajax({ url: "./dat ...

How to retrieve the Vue instance within a Laravel Inertia component

I am facing a challenge in extracting data from a dynamic HTML containing interpolation within a Vue component using Inertia. Here is a snippet of my code: <template> <div v-if="parsed" v-html="parsed"></div> </t ...