Vue-chartjs: Computed object won't populate chart

Created on 15 Aug 2017  ·  19Comments  ·  Source: apertureless/vue-chartjs

Expected Behavior

Passing a prop array and computing a data value from it to populate a chart should work.

Actual Behavior

Empty chart.

Looking in vue console tools, I see that my computed object is present and (seemingly) valid:

actionbarlabels:Object
  datasets:Object
    data:Array[4]
      0:4
      1:1
      2:2
      3:1
  labels:Array[4]
    0:"call"
    1:"join"
    2:"attend meeting"
    3:"attend march

And my template code looks like this:
<bar-chart :data="actionbarlabels" :options="{responsive: true, maintainAspectRatio: false}"></bar-chart>

Environment

  • vue.js version: 2.3.4
  • vue-chart.js version: 2.8.2
  • npm version: 4.2.0
  • quasar version: 0.14.0
Need Repo ❓ question

Most helpful comment

Oh, you are working with an API ?
Well, please keep in mind that if you're using api calls with axios or fetch that they are async!

So your chart component will get created and mounted before your data arrives.

You could use a loading state.

So in your data() you define

return {
  loaded: false
}

and in your api call (if you're using axios) you could set it it to true.

axios.get(`https://api.com/my-endpoint`)
    .then(response => {
        this.rawData = response.data
        this.loaded = true
    })
    .catch(err => {
        ....
    })

And then add an v-if="loaded" to your chart component. So it will only be shown if your data is complete.

Another way would be to add a watcher and rerender the chart if your computed prop change.

You can check out the resources in the docs. There are some tutorials on how to interact with APIS

http://vue-chartjs.org/#/home?id=resources

All 19 comments

Please provide a minimal jsfiddle / codepen for reproduction.

I don't have much experience setting up codepens, but I copied one and modified it to present the same issue (I think): https://codepen.io/ssuess/pen/zdPqGW

In playing around with the codepen, I found the problem for that simple example anyway: I had to add array brackets around object brackets on the data object before passing it back.

so {data} did not work, but [{data}] did....

But in my own code doing the same thing does not fix it. I am still investigating.

I'm stumped. If I put the EXACT SAME data into the data element, the chart will render. But if I leave it in a computed property only the chart title (label) in datasets array will render on a blank chart. See below how my computed object is identical to the data one (except for the _meta element which I assume is added by the plugin itself when a successful chart is drawn). Any ideas why this might be happening?
screen shot 2017-08-15 at 3 06 00 pm

Do you have any examples of a computed property being used in a chart that I could look at?

Found this on stackexchange which seems to describe almost exactly the same problem, but trying their solution did not work for me.

I have been examining this further, and it is definitely related to the prop data being passed down from the parent. It is for some reason inaccessible to the vue for the chart (although it is accessible and computing proper values as shown above in the debugger). When I copy my data to the data object and then compute THAT, it works fine. So somehow the prop with data I am passing down the chart refuses to see/use.

I give up. At least chartist works, I will content myself with that for the time being. Thanks anyway.

Hey.
I will try to reproduce it, and see where the problem is.
Generally it should work with computed properties. I used them in here
https://medium.com/@apertureless/wordpress-vue-and-chart-js-6b61493e289f

import { Bar } from 'vue-chartjs'
export default Bar.extend({
  props: ['labels', 'datasets'],
  computed: {
    'chartdata': function () {
      return {
        labels: this.labels,
        datasets: this.datasets
      }
    }
  },
 mounted () {
    this.renderChart(this.chartdata, 
    {responsive: true, maintainAspectRatio: false})
  }
})

Thanks, but as I said above, the problem seems not to be with computed properties per say, but with the prop (array) being passed down (even though it does pass down for my computed element in the vue dev tools). I notice in your example above your don't specify the prop as array btw, which I was under the impression you had to do for it to work in that case, no?

yes, trying with your notation above fails for me, I am curious how you passed labels and datasets in that code since they are not defined as arrays?

What do you mean, they are not defined as an array?

The labels and datasets are arrays.
Or you do mean the vue prop type-check?


<?php if(have_rows('datasets')): ?>
  <?php
    $datasets = [];
   ?>
<?php while ( have_rows('datasets') ) : the_row();
    $datasets[] = array(
      'label' => get_sub_field('dataset_label'),
      'backgroundColor' => get_sub_field('dataset_color'),
      'data' => explode(', ', get_sub_field('dataset_data'))
    );
  endwhile;
$labels = get_field('x_axis');
  $legend = get_field('legend');
$chartDatasets = htmlspecialchars(json_encode($datasets));
  $chartLabels = htmlspecialchars(json_encode(explode(', ', $labels)));
?>
<section class="chart-box text">
  <div class="text__wrapper">
    <bar-example
      :labels="<?= $chartLabels; ?>"
      :datasets="<?= $chartDatasets; ?>" >
    </bar-example>
  </div>
</section>
<?php endif; ?>


Well without seeing your code, parent + chart components, its hard to debug.
🙈

I'm sorry, I am new to Vue and I was under the impression that one was required to define prop type as array ie props: { labels: { type: Array }} I will try without. Also, I will try to simply my code and upload it here, thanks for looking at this, I appreciate it.

Oh, I see. No, this is only for type checking.
You can define the type of a prop and vue will check it and if it missmatches, it will throw an error.

If you don't define a type, the type will be any and you can pass everything into it.

You can also make own prop validation methods.

I have spent the last few hours looking at this, and have pinpointed the problem, but not a solution.

If I populate the parent with a hand typed array to pass down as my prop, ie:

items: [
        {
          'itemID': '1',
          'myitem': 'something_red'
        },
        {
          'itemID': '2',
          'myitem': 'something_red'
        },
        {
          'itemID': '3',
          'myitem': 'something_blue'
        },
        {
          'itemID': '4',
          'myitem': 'something_green'
        },
        {
          'itemID': '5',
          'myitem': 'something_red'
        },
        {
          'itemID': '6',
          'myitem': 'something_blue'
        }
      ]

And then perform my computed function on that, it WILL populate my bar chart. But if my prop ("items" in this case) is an array returned from a call to my api, it will NOT populate the chart, even though the calculated data looks just fine in dev tools. So there is something about the formatting of the array that the bar chart refuses to render. I have copied the array directly from the dev tools and pasted it into the data array of the parent, and I do get eslint warnings, but only about using single quotes over doubles. Other than that, it looks identical and I can't figure out why that would make a difference to the bar render.

Oh, you are working with an API ?
Well, please keep in mind that if you're using api calls with axios or fetch that they are async!

So your chart component will get created and mounted before your data arrives.

You could use a loading state.

So in your data() you define

return {
  loaded: false
}

and in your api call (if you're using axios) you could set it it to true.

axios.get(`https://api.com/my-endpoint`)
    .then(response => {
        this.rawData = response.data
        this.loaded = true
    })
    .catch(err => {
        ....
    })

And then add an v-if="loaded" to your chart component. So it will only be shown if your data is complete.

Another way would be to add a watcher and rerender the chart if your computed prop change.

You can check out the resources in the docs. There are some tutorials on how to interact with APIS

http://vue-chartjs.org/#/home?id=resources

OMFG! That was it!!! Thank you!!! Sorry to have put you through all of this.

You're welcome! ✌️

How can i get v-if="loaded" working with vuefire?
vuefire doesn't really make API calls but just binds to Firestore.

so, this does not work:

 firestore() {
 return {
    tweetdata: db.collection('tweets').where('screen_name', '==', this.twitter_screen_name)
    }
    this.loaded = true
  },

I have read dozens of questions. threads, tutorials etc but the computed properties loads first and that seem to be it.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

egorzekov picture egorzekov  ·  4Comments

DavidSotoA picture DavidSotoA  ·  3Comments

syxolk picture syxolk  ·  5Comments

kurbar picture kurbar  ·  4Comments

Sykomaniac picture Sykomaniac  ·  3Comments