Enhance your VueJs application with Chart.js without having to rely on refs for seamless reactive

Currently, I am delving into the world of VueJs and experimenting with Chart.js (https://github.com/apertureless/vue-chartjs). I attempted to make a doughnut chart reactive, but I achieved this using the ref property which I suspect may not be the best practice. My main query is whether it's true that avoiding $refs is advisable in such scenarios.

My initial hurdle was the lack of understanding about mixins. The only example I found on how to use vue-chartjs reactively included its use (https://github.com/apertureless/vue-chartjs/blob/master/src/examples/ReactiveExample.js can be referred for context). To overcome this, I created a method called updateData within my Vue component which essentially resets the chartData and then sets it to the prop data. Here is a snippet of my code:

chart.blade.php (web view):

<html>
    <head>
        <meta charset="utf-8">
        <title>Testchart</title>
        <link rel="stylesheet" href="css/app.css">
    </head>
    <body>
        <div id="app">
            <h1>Testchart</h1>
            <doughnut :data="doughnut_data" :options="doughnut_options" ref="chart"></doughnut>
            <button-reduce v-on:numberreduced="reduce"></button-reduce>
        </div>
        <script src="js/app.js" charset="utf-8"></script>
        </body>
</html>

app.js:

/**
 * First we will load all of this project's JavaScript dependencies which
 * includes Vue and other libraries. It is a great starting point when
 * building robust, powerful web applications using Vue and Laravel.
 */

require('./bootstrap');

/**
 * Next, we will create a fresh Vue application instance and attach it to
 * the page. Then, you may begin adding components to this application
 * or customize the JavaScript scaffolding to fit your unique needs.
 */



Vue.component('doughnut', require('./components/testDoughnut.vue'));
Vue.component('button-reduce', require('./components/button.vue'));

const app = new Vue({
    el: '#app',
    data: {
        doughnut_data: {
                labels: ['VueJs', 'EmberJs', 'ReactJs', 'AngularJs'],
                datasets: [
                    {
                        backgroundColor: [
                            '#41B883',
                            '#E46651',
                            '#00D8FF',
                            '#DD1B16'
                        ],
                        data: [40, 20, 80, 10]
                    }
                ]
            },
        doughnut_options: {
            responsive: true, 
            maintainAspectRatio: false
        }
    },
    methods: {
        reduce() {
            this.doughnut_data.datasets[0].data[2] = this.doughnut_data.datasets[0].data[2] - 5;
            this.$refs.chart.updateData();
        }
    }
});

Last but not least, let me introduce my Vue component testDoughnut.vue

<script>
import { Doughnut, mixins } from 'vue-chartjs'

export default Doughnut.extend({
  mixins: [mixins.reactiveData],
  props: ["data", "options"],
  data() {
    return {
      chartData: ''
    }
  },
  created() {
     this.updateData();
  },
  mounted () {
    this.renderChart(this.chartData, this.options)
  },
  methods: {
    updateData() {
      this.chartData = {}; // without this step, it does not work (no reactive behaviour). Why is this necessary?
      this.chartData = this.data;
   }
  }
})

</script>

The following questions have emerged:

  1. (from above): Is steering clear of $refs indeed recommended?
  2. Why is it challenging to directly update chartData from my webview? Using :chartData="doughnut_data" did not yield results, instead I had to employ a custom prop 'data'
  3. In my testDoughnut.vue, why is it essential to first reset chartData to an empty JSON object before assigning it to this.data? This seemed unnecessary based on my experience in desktop development (C#) where I could just write this.chartData = this.data.
  4. Is there a more efficient alternative to handling this issue rather than relying on ref as I have done?

Answer №1

Greetings! I am the creator of vue-chartjs.

Exploring the Mixins: Within Vue, mixins serve to extract logic and functionality into separate files for easy reuse.

As outlined in the documentation, there are two primary mixins available:

  • reactiveProp
  • reactiveData

The need for these mixins arises from different scenarios where data is passed to the chart component. For instance, in a Laravel environment, data may be directly passed as props to the component.

<my-chart :chart-data="..."></my-chart>

On the other hand, when dealing with APIs and fetching data, the chart data becomes a variable within the data() function of Vue rather than a prop.

Solution

A simpler approach is to leverage the reactiveProp mixin instead.

<script>
import { Doughnut, mixins } from 'vue-chartjs'

export default Doughnut.extend({
  mixins: [mixins.reactiveProp],
  props: ["options"],
  
 
  mounted () {
    this.renderChart(this.chartData, this.options)
  }
 
})

</script>

This mixin will create a prop named chartData and monitor changes to it. Any updates in the data will trigger either an update or re-rendering of the chart. Additionally, if new datasets are added, the chart must be re-rendered.

Answering Your Inquiries

  1. If you utilize the correct mixin, there's no need for $ref.
  2. To use camelCase in templates, remember to include a dash '-'
  3. If duplicating the data attribute causes issues, it could be due to a race condition where data is not set in the create() hook of Vue. Refer to https://v2.vuejs.org/v2/guide/instance.html#Lifecycle-Diagram for further insights.

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

Passport sessions do not retain persistence

Having some trouble implementing OAuth 2.0 login where the sessions don't persist after authentication is a common issue. Additionally, there seems to be a problem with the app getting stuck in the routes/bnetauth.js file during the redirect in the ca ...

Display a partial form in Rails using Ajax

There is a form displayed in the image below: Next, I aim to render this partial from an ajax call, specifically from .js.erb. However, I am unsure how to pass an object to f from the partial. Take a look at the image below for reference: Is there a way ...

Exploring the data-* attribute in jQuery

Currently, I have a form structured as follows: <div data-role="page" data-last-value="43" data-hidden="true" data-bind='attr : {"name":"John"}'></div> My objective is to modify the name attribute from "John" to "Johnny". I am att ...

Is there a way to retrieve the data instead of receiving an undefined result when making an asynchronous call?

subject in user.subjects = subjects below is undefined instead of being an array of subjects. Context: I am working with three database tables - users, subjects, and a relationship table between users and subjects known as users_subjects. The objective i ...

struggling to transfer information from JavaScript to Jade within the Node.js environment

Currently, I am retrieving a row from a Cassandra table called "emp". My objective is to pass the data retrieved from the JavaScript file to a Jade file in order to display this information on the user interface. In my JavaScript function: router.get(&a ...

jQuery's Offset().left is experiencing some issues and not functioning correctly

Do you have a question about the jQuery offset() function? On my website, I utilize it to show an "email a friend" window when the email icon is clicked. However, the problem is that the window ends up stuck to the right side of the browser's window ...

Utilizing AJAX to amplify the worth of plupload's echo capabilities

Greetings! Here is the JavaScript code I am using for plupload var uploader = new plupload.Uploader({ runtimes : 'html5,flash,silverlight,html4', browse_button : 'pickfiles', // you can pass in id... container: document.getElementById( ...

When an element is dragged within the mcustomscrollbar container, the scroll does not automatically move downward

I am facing an issue where I have multiple draggable elements inside a Scrollbar using the mcustomscrollbar plugin. When I try to drag one of these elements to a droppable area located below the visible area of the scroller, the scroll does not automatical ...

Having trouble with Javascript in getting one-page scroll navigation to work?

Hey there, I am working on creating a one-page scroll navigation with some basic javascript to add a smooth animation effect that takes 1 second as it scrolls to the desired section. However, I seem to be experiencing an issue where it's not functioni ...

Guide to activating MySQL query in Express

After creating a Nodejs Express app with a button on the client side, I want to execute a SQL query on the server side when the button is clicked. Is there a method to achieve this? The code in index.ejs: <button onclick='add()'>+1</but ...

Facing unexpected behavior with rxjs merge in angular5

import { Observable } from 'rxjs/Observable'; import 'rxjs/add/observable/merge'; this.data = this.itemsCollection.valueChanges() this.foo = this.afs.collection<Item>('products') .doc('G2loKLqNQJUQIsDmzSNahlopOyk ...

Testing the activated lifecycle in jest can be done by following a few simple steps

I'm facing an issue with testing the activated lifecycle in my Vue file. The code snippet I have is as follows: activated(): void { this.name = “”; this.emailAddress = “”; this.birthdate = “”; } I want to create a Jest test that checks if ...

Arranging serialized information from a tabular format and retrieving specific data

: I'm currently attempting to utilize an AJAX POST request to send data from a dynamic webpage that includes information gathered from a table form, a date selection box, and comment text input. The webpage is generated as a PHP file on a GET request ...

The "Open in new tab" feature seems to be missing for links when using Safari on iOS

My webapp contains links structured like this: <a href="/articles/">Articles</a> I am using JavaScript to control these links within my app: $(document).on("click", 'a', function(ev) { ev.preventDefault(); ev.stopPropagat ...

Navigating following a JQuery AJAX request in PHP

After clicking the login button, I utilize JQuery's POST method to retrieve data from login.php to check if the login was successful. If it fails (no user found), the appropriate message is displayed. However, when attempting to redirect a user (whic ...

developing a dropdown menu feature

I'm struggling with a small issue related to my drop-down menu function. My goal is to hide the visibility of a menu tab after it has been clicked for the second time. Below is the code snippet I've been working on: HTML:- <nav class="clea ...

Troubleshooting JavaScript for Sidebar Disappearance due to marginRight and display CSS Issue

I need to adjust the layout of my website so that the sidebar disappears when the window is resized below a certain width, and then reappears when the window is expanded. Here is the HTML code: <style type="text/css"> #sidebar{ width:290 ...

Avoid updating the callback in every update by using React's useEffect

Is there a way to avoid continuously updating a callback in useEffect?. For instance, I am subscribed to an event with geofire, which listens for changes and receives locations. I want to update my state without subscribing every time there is an update. ...

Styled-Component: Incorporating Variables into Styled-Component is my goal

Currently, I am working on an app and have created a separate file for styling. I decided to use style-components for custom CSS, but faced an issue where I couldn't access variables instead of HEX values. Even after storing color values in a variable ...

Executing JavaScript functions within static files in Django

I can't figure out why I'm unable to invoke a javascript function when clicking my Bootstrap button in a Django project. In my directory, I have set up the static folder as "main/static/main/js/script.js". While I can successfully load the stati ...