i am trying to use my firestore database data in vue chart but it is showing error with not defined
<vx-card title="PLACEMENT ANALYSIS" class="mb-base" >
<div class="mt-5">
<e-charts :options="bar" ref="bar" theme="ovilia-green" auto-resize />
</div>
</vx-card>
</template>
<script>
import ECharts from 'vue-echarts/components/ECharts'
import 'echarts/lib/component/tooltip'
import 'echarts/lib/component/legend'
import 'echarts/lib/chart/bar'
import theme from './theme.json'
import firebase from 'firebase/app'
import 'firebase/auth'
import "firebase/firestore"
ECharts.registerTheme('ovilia-green', theme)
export default {
data() {
return {
arr:[],
l:50,
r:30,
bar: {
legend: {},
tooltip: {},
dataset: {
// Provide data.
source: [
['Product', 'Eligible Students', 'Placed Students', ],
['B.Tech', ],
['MBA', this.random2(),this.random3()],
['B.com', this.random2(),this.random3()],
['MSc.', this.random2(),this.random3()],
['Others', this.random2(),this.random3()]
]
},
// Declare X axis, which is a category axis, mapping
// to the first column by default.
xAxis: { type: 'category' },
// Declare Y axis, which is a value axis.
yAxis: {},
// Declare several series, each of them mapped to a
// column of the dataset by default.
series: [{ type: 'bar' }, { type: 'bar' }]
},
}
},
beforeCreate(){
let u = firebase.auth().currentUser
firebase.firestore().collection('Colleges').doc(u.uid).get().then(doc =>{
this.arr = doc.data()
console.log(this.arr)
})
},
methods: {
random2() {
return[ this.arr.eligible]
},
random3(){
return[this.arr.placed]
}
},
components: {
ECharts
},
computed:{
chart(){
console.log(this.arr)
return this.arr
}
}
}
</script>
here eligible and placed are fields in arr and is visible in beforeCreate(),
but the chart is showing eligible is undefined and chart is not visible.
i tried using seperate varibales e.g l and r in data return field but it still shows undefined .
I am importing echart on different page as
<echarts-bar-chart></echarts-bar-chart>
<script>
import EchartsBarChart from '../charts-and-maps/charts/echarts/EchartsBarChart.vue'
<echarts-bar-chart></echarts-bar-chart>
Components:{
EchartsBarChart
}
</script>
arr is an array and you are trying to use a property arr.eligible that does not exist on an array. Do you want an item property, such as arr[0].eligible?
You might also want to confirm the this in your async callback is actually your component. Sometime a closure is needed to capture it.
You need to make sure this refers to your component. Try to capture it in a closure. Usually the lambda works, but sometimes there are issues.
const that = this;
firebase.firestore().collection('Colleges').doc(u.uid).get().then(doc =>{
that.arr = doc.data()
console.log(that.arr)
console.log(that)
})
Related
I'm new using Vuejs so I have a simple page with an input and button like
<input type="text" value="10" v-model="model.rowsPerPage">
<button #click="setNewValue()"> </button>
<script lang="ts">
import { useContact } from '#/composition/useContact'
import { ContactModel } from '#/services/modules/contact/contact'
import { defineComponent, reactive } from '#vue/composition-api'
export default defineComponent({
name: 'Contact',
setup() {
const model = reactive<ContactModel>({
pageNumber: 1,
rowsPerPage: 10,
searchBy: null,
staringDate: null,
endingDate: null,
})
const {
data: contactList,
totalItems: totalItems,
isLoading: isLoading,
error: error,
} = useContact(model)
return {
contactList,
model,
isLoading,
totalItems,
error,
}
},
methods: {
setNewValue() {
model.rowsPerPage = 20
},
},
})
</script>
So what I want to do, is update the input value by 10 if the button is clicked, so as you can see I add a method at the end of the script
methods: {
setNewValue() {
model.rowsPerPage = 20
},
},
But it throws me an error:
Cannot find name model
Why I can't access to const model declared at the top of script? How can I solve this? Regards
inside the methods you need to reference the "this" object to have access to what's returned in data or setup
but if you're using vue 3 with the composition api, you can simply define the function inside setup and return it, your template will then have access to it
(also, I think you should keep your component html inside a template tag)
I'm faced with a problem while implementing Highmaps.
In my vue project with Webpack, I followed each step explained https://github.com/highcharts/highcharts-vue to use Highmaps.
Here's my main.js file
//highchart
import HighchartsVue from 'highcharts-vue'
import Highcharts from 'highcharts'
import WorldMap from '#highcharts/map-collection/custom/world.geo.json'
import USMap from '#highcharts/map-collection/countries/us/us-all.geo.json'
import mapInit from 'highcharts/modules/map.js'
import DrillDown from 'highcharts/modules/drilldown.js'
mapInit(Highcharts);
DrillDown(Highcharts);
Highcharts.maps['world'] = WorldMap;
Highcharts.maps['us'] = USMap;
And, here's my vue file
<template>
<div>
<mymap :mapOptions="mapOptions.options"></mymap>
</div>
</template>
<script>
export default{
data(){
return {
mapOptions: {
options: {
chart: {
map: 'us',
events: {
drilldown: function(e){
var chart = this;
this.addSeriesAsDrilldown(e.point, {
data: 'world',
dataLabels: {
enabled: true,
format: '{point.name}'
}
})
},
drillup: function(){
}
}
},
series: [{
data: data,
joinBy: ['postal-code', 'code'],
dataLabels: {
enabled:true,
color: '#FFFFFF',
format: '{point.name}'
}
}],
}
}
}
},
}
</script>
Because the chart has 'chart': 'us' option, it renders US map first. Then, when I click any state (just for a test) it switches US map to world map.
It renders world map. However, it also render US map too. That is, it renders both two maps. How can I fix it??
I have 2 components OperatorsList and OperatorButton.
The OperatorsList contains of course my buttons and I simply want, when I click one button, to update some data :
I emit select with the operator.id
This event is captured by OperatorList component, who calls setSelectedOperator in the store
First problem here, in Vue tools, I can see the store updated in real time on Vuex tab, but on the Components tab, the operator computed object is not updated until I click antoher node in the tree : I don't know if it's a display issue in Vue tools or a real data update issue.
However, when it's done, I have another computed property on Vue root element called selectedOperator that should return... the selected operator : its value stays always null, I can't figure out why.
Finally, on the button, I have a v-bind:class that should update when the operator.selected property is true : it never does, even though I can see the property set to true.
I just start using Vue, I'm pretty sure I do something wrong, but what ?
I got the same problems before I used Vuex, using props.
Here is my OperatorList code :
<template>
<div>
<div class="conthdr">Operator</div>
<div>
<operator-button v-for="operator in operators" :op="operator.id"
:key="operator.id" #select="selectOp"></operator-button>
</div>
</div>
</template>
<script>
import OperatorButton from './OperatorButton';
export default {
name: 'operators-list',
components : {
'operator-button': OperatorButton
},
computed : {
operators() { return this.$store.getters.operators },
selected() {
this.operators.forEach(op =>{
if (op.selected) return op;
});
return null;
},
},
methods : {
selectOp(arg) {
this.$store.commit('setSelectedOperator', arg);
}
},
}
</script>
OperatorButton code is
<template>
<span>
<button type="button" v-bind:class="{ sel: operator.selected }"
#click="$emit('select', {'id':operator.id})">
{{ operateur.name }}
</button>
</span>
</template>
<script>
export default {
name: 'operator-button',
props : ['op'],
computed : {
operator() {
return this.$store.getters.operateurById(this.op);
}
},
}
</script>
<style scoped>
.sel{
background-color : yellow;
}
</style>
and finally my app.js look like that :
window.Vue = require('vue');
import Vuex from 'vuex';
import { mapState, mapGetters, mapMutations, mapActions } from 'vuex';
const store = new Vuex.Store({
state: {
periods : [],
},
mutations: {
setInitialData (state, payload) {
state.periods = payload;
},
setSelectedOperator(state, payload) {
this.getters.operateurs.forEach( op => {
op.selected = (op.id==payload.id)
})
},
},
getters : {
operators : (state) => {
if (Array.isArray(state.periods))
{
let ops = state.periods
.map( item => {
return item.operators
}).flat();
ops.forEach(op => {
// op.selected=false; //replaced after Radu Diță answer by next line :
if (ops.selected === undefined) op.selected=false;
})
return ops;
}
},
operatorById : (state, getters) => (id) => {
return getters.operators.find(operator => operator.id==id);
},
}
});
import Chrono from './components/Chrono.vue';
var app = new Vue({
el: '#app',
store,
components : { Chrono },
mounted () {
this.$store.commit('setInitialData',
JSON.parse(this.$el.attributes.initialdata.value));
},
computed: {
...mapState(['periods']),
...mapGetters(['operators', 'operatorById']),
selectedOperator(){
this.$store.getters.operators.forEach(op =>{
if (op.selected) return op;
});
return null;
}
},
});
Your getter in vuex for operators is always setting selected to false.
operators : (state) => {
if (Array.isArray(state.periods))
{
let ops = state.periods
.map( item => {
return item.operators
}).flat();
ops.forEach(op => {
op.selected=false;
})
return ops;
}
}
I'm guessing you do this for initialisation, but that's a bad place to put it, as you'll never get a selected operator from that getter. Just move it to the proper mutations. setInitialData seems like the right place.
Finally I found where my problems came from :
The $el.attributes.initialdata.value came from an API and the operator objects it contained didn't have a selected property, so I added it after data was set and it was not reactive.
I just added this property on server side before converting to JSON and sending to Vue, removed the code pointed by Radu Diță since it was now useless, and it works.
I have something like accepting parameters from a form and submitting. On submit, I dispatch an action and return the response and assign them to the parameters of the chart. But the change is not happening unless i press the submit button twice. But when i press the submit button, the label is getting updates as there is a v-model linked to the label select. But since there is no v-model for the bar-chart component, it is not getting updated.
<template>
<v-container fluid>
<v-card class="small" v-if="!empty">
<bar-chart :chart-data="datacollection"></bar-chart>
</v-card>
</v-container>
</template>
<script>
import BarChart from './BarChart.js'
import { mapGetters, mapActions } from "vuex";
export default {
name : "TestLegPerformance",
components: {
BarChart
},
data: () => ({
startdate: null,
enddate: null,
startmodal: false,
endmodal: false,
datacollection : {
labels: [],
datasets: [
{
label: '',
backgroundColor: '#C58917',
data: []
}
]
},
selected: [],
empty: true
}),
computed: {
...mapGetters({
planNames: "planNames",
details: "details" //parameter that i return from getters
})
},
mounted () {
this.getAllPlanNamesAction();
},
methods: {
...mapActions(["getAllPlanNamesAction","getDetails"]),
//assigning values to the chart parameters
changeData(){
this.empty = false;
let collectionClone = Object.assign({}, this.datacollection);
collectionClone.datasets[0].label = this.selected;
collectionClone.labels = this.details.months;
collectionClone.datasets[0].data = this.details.sub_count;
this.datacollection = collectionClone;
console.log('Collection Clone: ',collectionClone)
},
// form submit action
submitAction(){
this.empty = true;
console.log("Plan: ",this.selected);
console.log("Start Date: ",this.startdate);
console.log("End Date: ",this.enddate);
this.$store.dispatch('getDetails',
[this.selected,this.startdate,this.enddate])
this.changeData();
}
}
}
</script>
Chart.js and Vue Chart.js are not reactive by default.
See this in the Vue Chart.js docs
See this example
So after a lot of tries, I got it to work by redirecting the submit button to two different functions and adding a timeout between those two functions.
I have a vue application and a function that pushes a router and pass data to another router component.
passData: function () {
EventBus.$emit('passName', this.tableRow[0]);
this.$router.push('/analytic-two');
}
Then the other component.
<template>
<p>
This is Data passed from chart component {{passedRow}}
</p>
</template>
<script>
import { EventBus } from '../event-bus.js';
export default {
data() {
return {
passedRow: [
{
"name": "",
"numSongs": "",
"Year": ""
}
],
name: '',
id: '?',
};
},
created: function () {
const self = this;
EventBus.$on('passName', function (value) {
self.passedRow = value;
console.log(self.passedRow);
});
},
}
</script>
I know the data is coming through and its being logged but i can't figure out how to display it in my template does anyone have any ideas.
I would recommend to not using "=" operator instead of cleaning the reactive array and then fill it with the new values
self.passedRow.splice('deleteCount');
self.passedRow.push(...value); //pushes all the values in the value-array
This way you will at least be able see the progress.
You can also force a DOM-Update after setting the new value, but this should be unlikely in this case. To do so call in the component this.$forceUpdate()