Reputation: 141
I am trying to do communication between two components using $emit and $on:
I am unable to communicated between the two components and unable to update highcharts-chart in component-B from click event in component-A.
JavaScript Code for Component-A:
import Vue from 'vue';
const bus = new Vue();
const pause = ms => new Promise(resolve => setTimeout(resolve, ms));
export default {
data: () => ({
active: [],
avatar: null,
open: [],
users: [],
}),
computed: {
items() {
return [
{
name: 'Users',
children: this.users,
},
];
},
selected() {
if (!this.active.length) return undefined;
const id = this.active[0];
return this.users.find(user => user.id === id);
},
},
methods: {
fetchData() {
const id = this.active[0];
this.parts = this.users.find(user => user.id === id);
bus.$emit('new_parts', this.parts.data);
console.log(this.parts.data);
},
async fetchUsers(item) {
// Remove in 6 months and say
// you've made optimizations! :)
await pause(1500);
return fetch('http://localhost:8081/api/toppartsdata')
.then(res => res.json())
.then(json => (item.children.push(...json)))
.catch(err => console.warn(err));
},
},
};
JavaScript Code for Component-B:
import VueHighcharts from 'vue2-highcharts';
import Vue from 'vue';
const bus = new Vue();
const asyncData = {
name: 'Prediction Chart',
marker: {
symbol: 'circle',
},
data: [],
};
export default {
components: {
VueHighcharts,
},
data() {
return {
options: {
chart: {
type: 'spline',
title: '',
},
xAxis: {
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
},
yAxis: {
title: {
text: 'LINECOST',
},
labels: {
formatter() {
return `${this.value}°`;
},
},
},
tooltip: {
crosshairs: true,
shared: true,
},
credits: {
enabled: false,
},
plotOptions: {
spline: {
marker: {
radius: 4,
lineColor: '#666666',
lineWidth: 1,
},
},
},
series: [],
},
};
},
methods: {
test() {
// eslint-disable-next-line func-names
bus.$on('new_parts', (data) => {
alert(value);
});
},
load() {
// eslint-disable-next-line func-names
bus.$on('new_parts', function (data) {
this.asyncData.data = data;
});
const { lineCharts } = this.$refs;
lineCharts.delegateMethod('showLoading', 'Loading...');
setTimeout(() => {
lineCharts.addSeries(asyncData.data);
lineCharts.hideLoading();
}, 2000);
},
},
};
I want to be able to update my highcharts timeline graph using click events from component-A and update the data coming from the event to component-B everytime click the new button.
Upvotes: 0
Views: 523
Reputation: 7372
Your last code is almost correct, however here is the wrong part:
Wrong code:
created() {
bus.$on('new_user', (data) => { this.series = data; });
}
this.series
is not referring to series data, instead, you're adding a new property to the whole component object. In your case it should look like that:
Correct code:
created() {
bus.$on('new_user', (data) => { this.options.series[0].data = data; });
}
I prepared you an online example using highcharts-vue official Highcharts wrapper for VUE which I recommend you. There you will find working code with communication between components.
Demo:
https://codesandbox.io/s/r0qmqjljwq
Upvotes: 0
Reputation: 141
Below is the updated code for my highcharts component:
<template>
<div>
<vue-highcharts :options="options" ref="lineCharts"></vue-highcharts>
</div>
</template>
<script>
import VueHighcharts from 'vue2-highcharts';
import { bus } from '../../../main';
export default {
props: {
partsdata: {
type: Array,
},
},
components: {
VueHighcharts,
},
data() {
return {
options: {
chart: {
type: 'spline',
title: 'Hassaan',
},
xAxis: {
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
},
yAxis: {
title: {
text: '',
},
labels: {
formatter() {
return `${this.value}°`;
},
},
},
tooltip: {
crosshairs: true,
shared: true,
},
credits: {
enabled: false,
},
plotOptions: {
spline: {
marker: {
radius: 4,
lineColor: '#666666',
lineWidth: 1,
},
},
},
series: [],
},
};
},
created() {
bus.$on('new_user', (data) => { this.series = data; });
},
};
</script>
Upvotes: 0
Reputation: 536
The easiest way to handle is to use the this.$root to emit and listen to the event:
To emit the event from component-a:
this.$root.$emit('new_parts', this.parts.data)
To listen to the event on component b:
mounted() {
this.$root.$on('new_parts', (data) => {
//Your code here
});
},
Please add the onclick in the mounted method.
Here is a good article on events on Vue: https://flaviocopes.com/vue-components-communication/
Upvotes: 0
Reputation: 259
If this is the real code you're using in both components, then it doesn't work because you're creating 2 different buses instead of reusing the same bus for events.
Try pulling it out in a separate file, such as bus.js
, then export it and import it in the components where you need to interact with it:
// bus.js
export default new Vue()
// Component A
import bus from './bus'
bus.$emit('new_parts', this.parts.data)
// Component B
import bus from './bus'
bus.$on('new_parts', (data) => {
alert(value);
})
Let me know if something doesn't make sense.
Upvotes: 2