Im trying to make a c3 chart in my vuejs project using the vue-c3 reusable component. the problem is in the data.column option i didnt know exactly how to pass dynamic values to it here's what i've done for now
<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
import VueC3 from "vue-c3";
import axios from "v/vue-http";
#Component<SalesChart>({
name: "SalesChart",
components: { VueC3 },
data() {
return {
handler: new Vue()
};
}
})
export default class SalesChart extends Vue {
salesData: object;
get salesValues(): array {
return Object.values(this.salesData);
}
get options(): object {
return {
data: {
columns: [['sales', 175,45,98,76]],
type: "area-spline"
},
tooltip: {
format: {
title() {
return `test title`;
}
}
}
};
}
mounted(): void {
this.handler.$emit("init", this.options);
this.getData();
}
getData(): void {
axios
.get("/sales_analytics/30")
.then(response => {
this.salesData = response.data.data;
});
}
}
</script>
so when i do
data: {
columns: [['sales', 175,45,98,76]],
type: "area-spline"
},
the graph renders correctly but when i try to pass the salesValues columns: [this.salesValues] i get an error telling : Error in mounted hook: "TypeError: Cannot convert undefined or null to object" i dont know what i could be doing wrong, any help would be appreciated.
Your error seems to point to:
salesData: object; // null or undefined
get salesValues(): array {
return Object.values(this.salesData); // throws
}
possible fix:
get salesValues(): array {
return (this.salesData && Object.values(this.salesData))
|| ['sales', 175,45,98,76];
}
get options(): object {
return {
data: {
columns: [this.salesValue],
type: "area-spline"
},
tooltip: {
format: {
title() {
return `test title`;
}
}
}
};
}
Related
I'm desperately trying to use my props 'datas' with a foreach.
When I put my data in a "test" data, it works.
Example :
data() {
return {
postForm: this.$vform({}),
test: [{"name":"Couleur yeux","id":3,"answer":null},{"name":"Hanches","id":6,"answer":"'Test'"}],
}
},
computed: {
},
methods: {
createForm() {
this.test.forEach((data) => {
if (data.answer) {
this.$set(this.postForm, data.id, data.answer)
}
})
}
},
But if I use my props directly, it doesn't work. I have a message "this.datas.forEach is not a function".
But my props has exactly the same data and the same structure as my "test" data.
Don't work:
this.datas.forEach((data) => {
if (data.answer) {
this.$set(this.postForm, data.id, data.answer)
}
})
I also tried to transform my props into data() but it doesn't work
data() {
return {
postForm: this.$vform({}),
test: this.datas
},
"this.datas.forEach is not a function"
This mean that datas is not an Array instance because forEach is method from array prototype.
Right now, this.datas does not exist. You never give this the state with the key datas.
It looks like you're trying to go through this.test, which is an array of objects. Is that right?
If that's the goal, you can do so:
data() {
return {
postForm: this.$vform({}),
test: [{"name":"Couleur yeux","id":3,"answer":null},{"name":"Hanches","id":6,"answer":"'Test'"}],
}
},
methods: {
createForm() {
let arrayOfAnswers = []
this.test.forEach((data) => {
if (data.answer) {
arrayOfAnswes.push(data.answer)
}
})
this.arrayOfanswers = arrayOfAnswers
}
},
So I have the following code in one of my components:
export default {
name: 'section-details',
components: {
Loading
},
mounted() {
if (!this.lists.length || !this.section_types.length) {
this.$store.dispatch('section/fetch_section_form_data', () => {
if (this.section) {
this.populate_form();
}
});
}
else if (this.section) {
this.populate_form();
}
},
computed: {
section_types() {
return this.$store.state.section.section_types;
},
lists() {
return this.$store.state.list.lists;
},
loading() {
console.log(this.$store.state.section.loading);
this.$store.state.section.loading;
}
},
.
.
.
}
As you can see I have a computed property for "loading" that retrieves the attribute from my vuex store for when doing an ajax request.
in my section vuex module i have this:
fetch_section_form_data({ commit }, callback) {
commit("isLoading", true);
sectionService
.fetch_form_data()
.then((data) => {
commit("isLoading", false);
commit("fetch_section_types_success", data.section_types);
commit("list/fetch_lists_success", data.lists, { root: true});
if (callback) {
callback();
}
})
.catch((err) => {
commit("isLoading", false);
})
;
}
then in my mutations for the module i have the following code:
mutations: {
isLoading(state, status) {
state.loading = status;
},
}
Finally in my component where I store the loading property I have this:
<Loading v-if="loading"></Loading>
Anyways, for some reason the Loading component isn't showing up. the console.log in the loading() method however, is returning true for this.$store.state.section.loading. So for some reason Vue isn't picking up that loading == true in the actual DOM. Any help would be appreciated.
You need to return the value from the computed property method:
loading() {
return this.$store.state.section.loading;
}
<div class="content-chart">
<chart :type="'line'" :data="lineData" :options="options"></chart>
</div>
Above is the template section for a component and below is the script.
<script>
import Chart from 'vue-bulma-chartjs'
import { Tabs, TabPane } from 'vue-bulma-tabs'
export default {
components: {
Chart
},
data () {
return {
persondata: {},
}
},
mounted () {
let parameter = this.$route.params.id
axios.get('/api' + parameter.toString()).then(response => {
this.persondata = response.data
})
},
computed: {
lineData () {
var sth = this.person.dates['date-values']
return {
labels: [9, 10, 11, 12, 13, 14, 15],
datasets: [{
data: sth,
label: 'Speed',
}]
}
}
}
</script>
So as you see this Vue component renders a chart from Chart.js on the page. The problem is when I get the response from the api and save it to the this.persondata variable, when the component is mounted I get "TypeError: this.persondata.dates is undefined". If I do this though:
data () {
return {
persondata: {
dates: {
'date-values': []
}
}
}
}
and I try to save the response.data.dates['date-values'] to this.persondata.dates['date-values'] and insert it into the dataset.data in computed() I don't get any chart.
What is the problem?
computed properties are calculated right away: they are calculated before your Ajax returns.
Since you only populate persondata when the Ajax returns, the first time the computed is calculated, persondata is {} (the value of initialization in data).
Quick fix: initialize with an empty dates object, so the computation doesn't throw that error (giving time for the Ajax to return, which will update the computed property automatically):
data () {
return {
persondata: {dates: {}}, // added empty dates property
}
},
I'm trying to access my data property in my Vue.js component. Looks like I'm missing something obvious.
Here is a short version of my code. StoreFilter.vue is a wrapper for matfish2/vue-tables-2.
<template>
<store-filter :selected.sync="storeIds"></store-filter>
</template>
<script>
import StoreFilter from './Filters/StoreFilter';
export default {
components: {
StoreFilter
},
data() {
return {
options : {
requestFunction(data) {
console.log(this.storeIds); //undefined
return axios.get('/api/orders', {
params: data
}).catch(function (e) {
this.dispatch('error', e);
}.bind(this));
},
},
storeIds: [],
}
},
watch : {
storeIds(storeIds) {
this.refreshTable();
}
},
methods : {
refreshTable() {
this.$refs.table.refresh();
}
}
}
</script>
How to get storeIds from requestFunction?
Use a closure, see rewrite below.
data() {
let dataHolder = {};
dataHolder.storeIds = [];
dataHolder.options = {
requestFunction(data) {
// closure
console.log(dataHolder.storeIds); // not undefined
return axios.get('/api/orders', {
params: data
}).catch(function (e) {
this.dispatch('error', e);
}.bind(this));
}
}
return dataHolder;
}
I recommend using the created() way to handle this.
export default {
// whatever you got here
data () {
return {
options: {}
}
},
created () {
axios.get('/api/orders', { some: params }).then(response => this.options = response.data)
}
}
I want to access getValue method from Chart object, but I get function undefined.
<template>
<div>
<canvas width="600" height="400" ref="canvas"></canvas>
</div>
</template>
<script>
import Vue from 'vue';
import Chart from 'chart.js';
import Axios from 'axios';
export default {
mixins: [DateRangeMixin],
props: {
// other props...
callback: false,
},
data() {
return {
chart: '',
};
},
mounted() {
// ...
},
methods: {
//other methods...,
getValue(data) {
if (data === 1) {
return 'Up'
} else if(data === 0) {
return 'Down';
}
},
render(data) {
this.chart = new Chart(this.$refs.canvas, {
type: 'line',
data: {
labels: Object.keys(data),
datasets: [{
// a lot of data ....
data: Object.values(data),
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true,
callback(label, index, labels) {
return this.getValue(label); // <-- Tried this and got: 'this.getValue is not a function'. I understand it bounces to new Chart object, but how to resolve this?
}
}
}]
}
}
});
},
},
};
</script>
I understand that it's because Chart is an object and this is pointing to it, but how do I resolve this and access my method from the callback ?
I imagine if that export default... would be set to a variable, then I could access my method via variable.methods.getValue , but in this scenario How can I achieve my goal ?
Right before you create the new Chart() assign this to a variable self: var self = this;.
You can then access your component properties throughself.