-
-
Notifications
You must be signed in to change notification settings - Fork 836
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rerender when data has changed #10
Comments
Well the chart does not update itself if new data arrives. However chartjs have methods to update the chart. From the docs: myLineChart.data.datasets[0].data[2] = 50; // Would update the first dataset's value of 'March' to be 50
myLineChart.update(); // Calling update now animates the position of March from 90 to 50. Inside your chart component you can access the chart object over So you can change the data You could also make a small update helper function, which listen on an event or something. |
great! I think this is just what I needed. Didnt know how to access the chart object. Will have a go at it and ad a watcher for the property. Thanks for a great package! |
Okey, so this is how I solved it. If you have any thoughts of improvement just let me know! Keep in mind that my use case was to be able to dynamically change the datasets/data of the graph. Solution:
To check what datasets is present i created an array containing the labels of the // MyLineChart.js
import { Line } from 'vue-chartjs'
export default Line.extend({
name: 'my-line-chart',
props: ['data'],
watch: {
'data': {
handler: function (newData, oldData) {
let chart = this._chart
let newDataLabels = newData.datasets.map((dataset) => {
return dataset.label
})
let oldDataLabels = oldData.datasets.map((dataset) => {
return dataset.label
})
if (JSON.stringify(newDataLabels) === JSON.stringify(oldDataLabels)) {
newData.datasets.forEach(function (dataset, i) {
chart.data.datasets[i].data = dataset.data
})
chart.data.labels = newData.labels
chart.update()
} else {
this.renderChart(this.data, this.options)
}
},
deep: true
}
},
data () {
return {
options: {
/* my specific data */
}
}
},
mounted () {
this.renderChart(this.data, this.options)
}
}) I think that this should be the default behavior for this plugin..? If you think so too just let me know and I'll make a PR. |
Sorry for the late reply. Pretty busy right now. |
Cool, I will take a look at it and send you a PR. 👍 |
hm.. I dont get anything when i enter the When I was looking at your code. It doesnt quite feel right to try to stick in a watcher and also add an optional data property. What do you think of me just adding a LiveDataLineExample.js an then maybe refer to that in the readme? |
Oh yeah, because the entry point index.js contains only the module exports. import Vue from 'vue'
import App from './examples/App'
/* eslint-disable no-new */
new Vue({
components: { App }
}).$mount('#app') If you want you can just add an example. I guess the best way to implement it, would be a shared mixin. Because the data prop, watcher and the logic for update or rerender would be the same for every chart. There were then two possibilities: Add the mixin to all base-charts so they all have this behaviour per default, or what's even cooler I think, to let people decide if they want the realtime updates. So they have to add the mixin to their own components. |
Hello, I am using v1.1.3 and I try to update chart view with
so is there any way to fix this? or the new version is coming? |
What excatly are you trying to do? |
Does this also work with vue-chartjs 1.x ? If not, are there other ways to make a chart reactive in 1.x? |
Yeah this should work with vue-chartjs 1.x, too. There are also two mixins in the develop branch Which abstract this logic for a data properties if you want to use like an api to get your data and for component props, if you want to pass the data through props. I think you can more or less copy paste this mixins into your local project, and just change the Or you make it by yourself. Its not a complicated logic. Just need to check if the data has changed and trigger the this._chart.update() or render(). |
Do you have the From vue docs:
Alternatively try: watch: {
data: function (val, oldVal) {
console.log('new: %s, old: %s', val, oldVal)
}
} |
@beebase me too. Do you solve it? |
@MissHoya are you implemented the watcher yourself or are you using the provided mixins? |
@apertureless I use vue.v1 and branch1.1,3,I don't provide mixins. My use is as follows: 2.import this and define a component 3.define chartData in parent component 5.I click and try to change chartData.datasets[0].label(Maybe this method is wrong). I see label has been changed in parent component with vue-tool, but error and no chart update. at the same time, I have a question: so I don't know where wrong. My English is so poor, please forgive me. |
My first thought is that your watch is triggering itself in an endless loop. You should try the mixin method. No need to build a watcher for your chartData. |
@MissHoya |
Can you provide a minimal repo for reproduction? It's really hard to tell, with only seeing small pieces of code. |
I set a repository in my github: https://github.com/MissHoya/vue-chart-example |
Hi @apertureless , I am experiencing similar issues with the reactiveProp mixin. I am updating the chartData prop asyn via an api call, in the axios callback. This doesn't trigger the watch or update chartData on the component side. If I put a breakpoint on where it is rendering, vue version: 2.1.10, Here is the code snippets. BarChart.js (component)
Parent file
Template
|
Well I am not sure, how the vue watcher reacts to async data. However I would not recommend using the mixin in this case. Because your data comes async and it could possibly overload the watcher. I would simply try events. Then you can use a finish callback or smth. send and finish event and then update or rerender the chart. |
I managed to update it by calling update on the component when the data is ready. |
just to let you know - this worked like a charm for me
|
Nice! Thanks for the info. |
@Andkoo were you able to do that without getting a "Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders..." error? |
@XavierAgostini You can't mutate a prop, or better to say - you can...but I don't recommend it. What's expected:You want to change some data, that are being sent from a parent component. You want to change them in a child component. What's actually happening:The child component receives some data from the parent component and changing them in the child component doesn't change them in the parent component, therefore whenever the parent component re-renders (let's say you change a route or something) the change to these data is lost. What should you do instead:Create a data property in the child component that references to the prop, that is used to pass data from parent component, then work with this data property like this:
(note that prop type or alternatively you can mutate the parent component data through an event emitter, or directly in the parent component etc. There are multiple ways to accomplish this. Please provide a reproduction link so I can look into it, I need to know how you want to mutate the prop. |
Thanks @Andkoo I will try that tonight. Here is my repo https://github.com/XavierAgostini/vue-finance . I'm trying to pass an object as a prop in my TFSA.vue component to a bar graph component. |
@XavierAgostini I got a 404 error. Is your repo public? Please provide a proper reproduction link. |
The markdown link is wrong: |
@apertureless ah thanks, my bad
no need to call a mixin, because I set my own watcher right inside the component to watch the changes to |
@Andkoo thank you that worked perfectly! |
After a few hours of frustration, I finally figured this out. I am creating a chart that has a variable number of labels and fields. I abandoned the seemingly buggy mixin , and just added my own listeners. Just in case anyone else has any confusion, if you're setting up following the examples, I ended up doing this: Vue.component 'bar-graph',
extends: VueChartJs.Bar
props: [
'chartInfo',
'chartLabels',
]
watch:
chartInfo:
handler: (to, from) ->
this.$data._chart.destroy()
this.renderChart(this.chartInfo, this.options)
chartLabels:
handler: (to, from) ->
this.$data._chart.destroy()
this.renderChart(this.chartInfo, this.options)
mounted: ->
chartOptions =
responsive: true
maintainAspectRatio: true
tooltips:
enabled: false
scales:
xAxes: [
ticks:
autoSkip: false,
maxRotation: 0,
minRotation: 90
]
@renderChart this.chartInfo,
chartOptions You'll note that |
Ended up just using: I just couldn't get |
hmmm |
Is there any update on this issue? I need help too.
It works perfectly like this, but when I try to use |
Out of context, but in case you stumble on this: be careful when you try to implement a watch handler. I had an error mentioning watch: {
chartData: {
handler: function () {
this.$data._chart.destroy()
this.renderChart(this.chartData, this.chartOptions)
},
deep: true,
immediate: false
}
}, |
I know it's bad solution but you can fixed this issue by toggle chart parent with true/false, |
Hi! I am using the
next
branch.I was wondering how I can make my charts reactive to the data that I enter through the
:data
property.So, what should I do to re-render/update a graph?
Edit:
And I do know that the data has changed. I can see that through Vue Devtools. So the new data is reactiv to the inside of my chart component. But there graph does not update when the new data arrives.
The text was updated successfully, but these errors were encountered: