Create a new Chart.js visualization using information retrieved from an external API

Seeking to initialize a Chart.js chart with an API, I've come across tutorials that update the data post page rendering. However, I wish to update the chart before the page renders, enabling me to view the initialized chart without any reload.

<template>
    <h3>Stacked</h3>
    <Chart type="bar" v-if="isReady" :data="stackedData" :options="stackedOptions"/>
</template>

<script>
import axios from "axios";
import {defineComponent, ref} from 'vue';
export default {
 
    data()  {  
 
       return {
              isReady: false,
              stackedData: {
                labels: ['A', 'B', 'C', 'D'],
                datasets: [{
                    type: 'bar',
                    label: 'Something',
                    backgroundColor: '#42A5F5',
                    data: this.list_all
                }, {
                    type: 'bar',
                    label: 'Another',
                    backgroundColor: '#66BB6A',
                    data: this.list_intersection
                }]
            },
           
            stackedOptions: {
                tooltips: {
                    mode: 'index',
                    intersect: false
                },
                responsive: true,
                scales: {
                    xAxes: [{
                        stacked: true,
                    }],
                    yAxes: [{
                        stacked: true
                    }]
                }
            },
            basicOptions: null,

//---------------------------------------------------
            all:[],
            list_intersection:[],
            list_all:[]
        }    
    },

    beforeCreate() {
            let apiKaderURL = 'http://localhost:4000/apiKader';
            axios.get(apiKaderURL).then(res => {

                this.all = res.data;
                this.saveData()
                this.isReady=true;
            }).catch(error => {
                console.log(error)
            });
        },

     methods:{
       saveData: function (){
          
          for (var i in this.all){
                if(this.all[i].id==='2' ){
                    this.list_all.push(this.all[i].someNumber)
                }
                if(this.all[i].id==='8'){
                    this.list_intersection.push(this.all[i].someNumber) 
                }                     
           }
           return this.list_all && this.list_intersection
       }
    }
}
</script>


In essence, I use Axios to fetch values, filter them accordingly, and then assign them back to the data property of the chart objects for initialization purpose.

Despite my efforts by utilizing beforeCreate, the chart fails to display any values even though I believe I am initializing the values prior to rendering.

I also experimented with using vue-chartjs, but it seems inadequate for Vue 3 or perhaps I made some error in the process.

Any insights on how I can achieve this would be greatly appreciated. Thank you in advance!

Answer №1

Although I haven't had the opportunity to work with Chart.js previously, I took the time to review the Installation, Integration, and Usage documentation. After going through it, I created an example tailored for you using Vue 2 with Vue CLI.

In this example, I utilized my App.vue SFC as the parent component for the child chart component known as ChartTest.vue. Inside the parent component, I imitated an API call delay by incorporating a 'setTimeout' function within the 'mounted' hook.

Here is a breakdown of the key components:

<template>
  <div id="app">
    <chart-test v-if="dataReady" :chartData="chartData" />
  </div>
</template>

<script>
  import ChartTest from '@/components/ChartTest'

  export default {
    name: 'App',
    components: {
      ChartTest
    },
    data() {
      return {
        chartData: [12, 19, 3, 5, 2, 3],
        dataReady: false
      }
    },
    methods: {
      getData() {
        this.dataReady = true;
      }
    },
    mounted() {
      // Simulate API call
      setTimeout(this.getData(), 2000);
    }
  }
</script>

For the ChartTest.vue component:

<template>
  <div class="chart-test">
    <h3>Chart Test</h3>
    <canvas id="my-chart" width="400" height="400" ref="chartref"></canvas>
  </div>
</template>

<script>
  import Chart from 'chart.js';

  export default {
    data() {
      return {
        myChart: null
      }
    },
    props: {
      chartData: {
        type: Array,
        required: true
      }
    },
    mounted() {
      this.myChart = new Chart(this.$refs.chartref, {
        type: 'bar',
        data: {
          labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
          datasets: [{
            label: '# of Votes',
            data: this.chartData,
            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
              }
            }]
          }
        }
      });
    }
  }
</script>

Answer №2

Remember that the lifecycle hooks, such as beforeCreate, do not actually delay the subsequent steps in the component's lifecycle, even if they are asynchronous. They simply serve as entry points to run code.

If you want to delay the rendering of a chart until the data is ready, use a v-if directive. This will prevent the chart from being rendered until the specified condition is met. You can create an isReady variable and set it to true once the data is saved:

<Chart type="bar" v-if="isReady" :data="stackedData" :options="stackedOptions"/>
data()  {  
  return {
    isReady: false,
    ...
  }
}
axios.get(apiKaderURL).then(res => {
  this.all = res.data;
  this.saveData()
  this.isReady = true;  // Triggering the `v-if`
})

(Not tested, but should work in theory)


Furthermore, remember that you cannot set a data property using another data property with this; it will result in undefined. Instead, set them to null:

data: this.list_all  // Incorrect usage, cannot reference `this` like that
data: null           // Correct approach

Set it to null and update the saveData method accordingly:

methods: {
  saveData() {
    const listAll = [];
    const listIntersection = [];

    for (var i in this.all){
      if(this.all[i].id==='2' ){
        listAll.push(this.all[i].someNumber)
      }
      if(this.all[i].id==='8'){
        listIntersection.push(this.all[i].someNumber) 
      }                     
    }
   
    this.stackedData.datasets[0].data = listAll;
    this.stackedData.datasets[1].data = listIntersection;
  }
}

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

Using checkboxes in an Express application

Currently, I am working on the task of parsing checkbox values into an array using express/ejs. Users are required to fill out a form and select checkboxes as shown below: Answer: Checkbox: The goal is to create two arrays from the input data: answer = ...

After completing the Spotify authentication process using implicit grant in a React application, the redirection is not functioning as

I am working on integrating Spotify authentication using the implicit grant method as outlined in their documentation. I have implemented the relevant code into a React component and successfully logged into Spotify. However, I am facing an issue where the ...

Iframe Loading at Lightning Speed

I have set up a script to load my iframe, but I noticed that the script loads the iframe content too quickly. Is there a way for me to configure it to preload all CSS images and content in the background before showing the full iframe content? Here is my ...

Steps for initializing and loading the Ace editor:

I've been attempting to utilize the Ace code editor library (), but I'm encountering some issues. The embedding guide suggests that the required js files should be loaded from Amazon's CDN. <script src="http://d1n0x3qji82z53.cloudfront.n ...

What steps can I take to ensure that when the user clicks the logout button, they are redirected to the home component?

Struggling to find a way to direct the user back to the Home component after logging out. The API functionality has been tested and is working properly. I'm unsure how to properly implement the logout method in the current context to allow for succes ...

Transform the display format of the input type date field from 'MM/DD/YYYY' to 'February 5, 2012' in a React.js application using Material-UI's TextField component

https://i.stack.imgur.com/9p7Mz.jpg I am working with a material-ui/ TextField date component and I am looking to maintain the current style and input method, but I need to adjust how the entered value is displayed to the 'en-us' format. const o ...

An issue with the THREE.js TextureLoader not functioning properly when deployed

After implementing the code below, my project is successfully rendering my background and avatar. However, when deploying on Netlify, the rendering does not function as expected. I have attempted using "../../", "./", and other variations, but the issue p ...

Navigating to the next sibling child in Angular 1 using Ui-router transition

I'm trying to figure out how to effectively transition between sibling states using $state.go() in ui-router. Imagine a child state with integer-based URLs: /parent/1, parent/2, parent/3 and so on I want to be able to navigate between these child st ...

Angular2 - Transforming SVG elements with dynamic styles using ng-style

I'm trying to create SVG lines using ng-repeat and need to adjust the translation of each line. However, I'm having trouble getting the style to apply using ng-attr-style. my-component.js: import {Component} from 'angular2/core'; @Co ...

Using a gogocartojs map in your JavaScript project

I have created a new project and am attempting to integrate gogocartoJs into it. While the project itself is functioning properly, I am experiencing issues with the map not displaying as expected. Although I have followed the provided guides, there seems ...

The image file that was uploaded to our S3 storage has been detected

I'm attempting to upload an image created by cropperjs to a DigitalOcean space. To achieve this, I am utilizing a pre-signed URL and performing a put request using Axios. The problem arises when I try to open the uploaded image, as it appears to be ...

I'm working on separating the functionality to edit and delete entries on my CRM model, but I'm having trouble finding a way to connect these buttons with my data fields

I am encountering some difficulties while trying to implement separate functionality for editing and deleting items on my CRM model. I have already created the necessary API in Angular, but I am struggling to bind these buttons with my field. Any assistanc ...

Navigate through chosen options by clicking on a button

It's a new day and I'm facing a simple challenge that seems complicated in the morning haze. I need to create a select dropdown with zoom percentage values, along with + and - buttons to navigate through the list. If I have the following setup: ...

Learn how to dynamically disable a button based on the input state matching an email pattern!

I'm facing an issue with my login form that has 2 input fields and a login button. One of the input fields requires a valid email pattern. If any of the input fields are left empty, the login button becomes disabled. However, when an incorrect email p ...

Fluctuating and locked header problem occurring in material table (using react window + react window infinite loader)

After implementing an Infinite scrolling table using react-window and material UI, I have encountered some issues that need to be addressed: The header does not stick to the top despite having the appropriate styles applied (stickyHeader prop). The header ...

Steps to refresh a .ejs page with updated information following an ajax request

I am in need of re-rendering my homepage.ejs with new data on the server side following an ajax request. Although I am aware that you can somehow re-render the elements in the ajax callback, I am interested in finding out if it is possible to simply re-ren ...

The JavaScript code in Three.js is experiencing issues when running in a secure HTTPS environment

After transitioning my website from http to https, I encountered an issue with one of my projects. The background using the Three.js library in this random generator does not show up when the URL is https. However, when the URL is http, the generator wor ...

Troubleshooting Tips for Node.js and MongoDB Socket Closure Issue

I'm running into an issue while working on the login system for my NodeJS application. Everytime I attempt to retrieve a collection, MongoDB throws me this unusual error. The Error Message [MongoError: server localhost:27017 sockets closed] name: &a ...

In the process of developing a matchmaking feature

Currently, I am working on a matchmaking system to find suitable opponents based on a user's trophies. Everything seems to be working fine until the if condition is triggered, which results in an infinite loop. const UserProfile = require("../sch ...

Converting a string to regular text in JavaScript (specifically in ReactJS)

When I fetch data from an API, sometimes there are special characters involved. For example, the object returned may look like this: { question : "In which year did the British television series &quot;The Bill&quot; end?" } If I save t ...