Chartjs + Vue.js - Cannot read property '_meta' of undefined - javascript

I am building an app using Vue.js + Chartjs. I am having a problem where I make a http call to a service to get data, parse it, and pass it into my Chartjs component. However, I keep getting the error Cannot read property '_meta' of undefined
Here are the relevant parts of my component:
<template>
<Chartjs :data="chartData" />
</template>
export default {
data () {
return {
chartData: false
}
},
created () {
this.getData()
},
methods: {
getData() {
const opts = {
url: 'some_url',
method: 'get'
}
request.callRoute(opts).then(results => {
this.chartData = results.data
}).catch(err => {
console.log(err)
})
}
},
components: {
Chartjs
}
}
Note - the chart renders fine if I hard code the chartData field with data that comes back from my request. However, it does NOT work if I make a http request first for my data.
Does anyone know what might be happening?
Thanks in advance!

Vue will render the component with the initial chartData (which is a boolean). You should use a v-if or other logic and render Chartjs component when you have the response. For example you can show a loading message/animation while the chartData is false.

Related

Vue prefetch data from separate backend

I have some queries from an API-Server that returns a json object that will be static over a user session, but not static forever.
It's a one-pager with Vue router.
How can I achieve that I:
can access this.myGlobals (or similar eg window.myGlobals) in all components, where my prefetched json-data from API-Server is stored.
My approach that is already working is to embed help.js via a mixin.
Oddly enough, I get hundreds of calls to this query. At first I thought that it only happened in the frontend and is chached, but the requests are actually sent hundreds of times to the server. I think it is a mistake of my thinking, or a systematic mistake.
i think the problem is, that the helper.js is not static living on the vue instance
main.js:
import helpers from './helpers'
Vue.mixin(helpers)
helpers.js:
export default {
data: function () {
return {
globals: {},
}
}, methods: {
//some global helper funktions
},
}, mounted() {
let url1 = window.datahost + "/myDataToStore"
this.$http.get(url1).then(response => {
console.log("call")
this.globals.myData = response.data
});
}
}
log in console:
call
SomeOtherStuff
(31) call
SomeOtherStuff
(2) call
....
log on server:
call
call
call (pew pew)
My next idea would be to learn vuex, but since its a easy problem, im not sure if i really need that bomb ?
You can use plugin to achieve this.
// my-plugin.js
export default {
install (Vue, options) {
// start fetching data right after install
let url1 = window.datahost + "/myDataToStore"
let myData
Vue.$http.get(url1).then(response => {
console.log("call")
myData = response.data
})
// inject via global mixin
Vue.mixin({
computed: {
myData () {
return myData
}
}
})
// or inject via instance property
Vue.prototype.$myData = myData
// or if you want to wait until myData is available
Vue.prototype.$myData = Vue.$http.get(url1)
.then(response => {
console.log("call")
myData = response.data
})
}
}
and use it:
Vue.use(VueResource)
Vue.use(myPlugin)

Assigning res.data to variable returns null

I am trying to make a GET request to an API, assign the response to a variable and console.log it. Currently I get null in the console and I don't know why. when I just console.log the res.data I get the data, but for some reason the value does not get assigned to the variable allBeers, how can I save the response to that variable and use it?
Here is my code:
<script>
import axios from "axios";
export default {
name: "BeerList",
data() {
return {
allBeers: null
};
},
created() {
axios.get("https://api.punkapi.com/v2/beers").then(res => {
this.allBeers = res.data;
});
console.log(this.allBeers);
}
};
</script>
Try this solution. axios.get is a promise, and console.log will happen before axios.get is completed. That's why you get null.
<script>
import axios from "axios";
export default {
name: "BeerList",
data() {
return {
allBeers: null
};
},
created() {
axios.get("https://api.punkapi.com/v2/beers").then(res => {
this.allBeers = res.data;
console.log(this.allBeers);
});
}
};
</script>
You are saving the response to 'allBeers' variable correctly. The "how to use it" part depends on what you want to do with the data. Vue's 'data' is reactive, so if you want to print it to console when it changes you should use Vue's watcher in your component:
watch: {
allBeers: function(value) {
console.log("my new beers:");
console.log(value);
}
}
As Vue is UI framework you might want to update your html with the new data, in which case you need to add html template to your component - it will be automatically re-rendered when 'allBeers' change:
template: `<span> {{ allBeers }} </span>`

getting a restful Api using the fetch() in Vuex

im really going through hard times trying to figure out how to get my API data through Vuex, is there some body whom has accurate bibliography of how to do this step by step, or even better help me with this code?
Formerly without using Vuex , but Vue all request worked perfectly, but now i dont understand clearly what i should do, here sharing part of my code:
data() {
return {
testArray: []
};
methods: {
getJsonData() {
fetch(
"https://app.ticketmaster.com/discovery/v2/events.json?countryCode=" +
this.countriesDrop +
"&apikey=xxxxxxxxxxxxxxxxxxxxxxxx",
{
method: "GET"
}
)
.then(response => {
return response.json();
})
.then(test => {console.log(this.testArray)
this.testArray = test._embedded.events;
})
.catch(err => {
console.log(err);
});
},
watch: {
countriesDrop: function(val) {
this.getJsonData();
}
},
As you can see in the request also is included an external element which make it changes attuning with the watcher and the value the user might asign.
I already got set Vuex and all else pluggins...just dont know how to act like , thus would appreciate an accurate link or tutorial either help with this basic problem resolved on detail step by step, .....thanks!
In your code there's nothing with Vuex. I guessed you want to set the state so that the getJsonData() method is called according to what's in the store.
Here's a snippet as an example of handling async in a Vuex environment.
const store = new Vuex.Store({
state: {
testArray: []
},
mutations: {
setTestArray(state, data) {
state.testArray = data
}
},
actions: {
getJsonData({
commit
}, countriesDrop) {
if (countriesDrop && countriesDrop !== '') {
fetch(`https://jsonplaceholder.typicode.com/${countriesDrop}`, {
method: "GET"
})
.then(response => {
return response.json();
})
.then(json => {
commit('setTestArray', json)
})
.catch(err => {
console.log(err);
});
}
}
}
})
new Vue({
el: "#app",
store,
computed: {
getDataFromStore() {
return this.$store.state.testArray
}
},
methods: {
getData(countriesDrop) {
this.$store.dispatch('getJsonData', countriesDrop)
}
}
})
<script src="https://cdn.jsdelivr.net/npm/es6-promise#4/dist/es6-promise.auto.js"></script>
<script src="https://unpkg.com/vuex#3.1.2/dist/vuex.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button #click="getData('todos')">GET TODOS</button>
<button #click="getData('albums')">GET ALBUMS</button>
<ol>
<li v-for="data in getDataFromStore">{{data.title}}</li>
</ol>
</div>
The point is that Vuex is a central element in a Vue-Vuex application. You can store app state, handle async and sync functions (actions, mutations) with it, and all your Vue components can rely on the state - that should be the "single source of truth".
So, you get your input from a component (the Vue instance in this snippet), and dispatch an action that is available in the Vuex store. If the action needs to modify the state, then you call a mutation to do that. With this flow you keep reactivity for all your components that use that state.
I used a computed to get data from the Vuex store, but getters can be set also.
This way you don't "pollute" your components with functions and data that should be in the store.

Pass data into vuejs template

I have a Laravel application with vuejs2 support. Im using the router component in the vuejs part. How can I send data like sessions from laravel to a vuejs template. In my blade template I use <router-view ></router-view> to call the vue router component. How can I add data.
Thanks for help!
The page which you want to load using vuejs router component, add a script in the footer section of that page. And after using router push command, please refresh the whole page.
Keep a flag like: loading. At first, keep it true to view some initial message, and when you'll get axios response then make it false. Based on this flag, show the data that you get from axios response. And of course update the initially declared data after getting the axios response.
Example:
<script>
export default {
data(){
return {
loading:true,
// Others Data
}
},
methods:{
function_name (){
this.$router.push('/');
window.location.reload();
}
},
mounted() {
var _this = this;
axios.get('/data').then(function (response) {
//others data update
_this.loading=false;
});
}
}
</script>
You can use axios to make a get request to your laravel app.
Example method:
data() {
return {
data: ''
}
},
methods: {
getData: function () {
axios.get("/data")
.then((response) => {
this.data = response.data;
}, (error) => {
})
}
},
Note that you need to import axios in order to work:
import axios form 'axios'
Then you need to handle the request on the server side

How to get the latest data from parent to child components after page refresh

I am working on a project and using Vue.js for the frontend. I have following code in the main.js file.
new Vue({ // eslint-disable-line no-new
//el: '#app',
router,
data () {
return {
friends: []
}
},
methods: {
getFriends: function () {
return this.friends;
}
},
created: function () {
this.$http.get('/user/' + this.getUserIDCookie('userID') +
'/friends').then(function (response) {
this.friends = response.data;
});
},
components: {
'nav-bar': require('./components/Navigation.vue')
},
template: `
<div id="app">
<nav-bar></nav-bar>
<router-view class="router-view"></router-view>
</div>`
}).$mount('#app');
In one of the pages(for ex. when the page is redirected to localhost/#/user/1/details, I am retrieving the friends' list from main.js like below:
<script type="text/babel">
export default {
name: 'profile',
data: function () {
return {
user: {},
friends: []
}
},
methods: {
// Some methods
},
created: function () {
this.friends = this.$root.getFriends();
}
}
</script>
The problem arises when I refresh the current page. After page refresh, this.friends is null/undefined because this.$root.getFriends() is returning null/undefined. I can move it to user component, but I want to keep it in main.js so that GET call is used once and data will be available to the whole application.
Any input regarding how to solve this issue would be great. I am using Vue 2.0.1
Really, what you want to do, is pass the data the component needs as props.
The dirt simple easiest way to do it is this.
<router-view class="router-view" :friends="friends"></router-view>
And in your profile component,
export default {
props:["friends"],
name: 'profile',
data: function () {
return {
user: {},
friends: []
}
},
methods: {
// Some methods
}
}
If you want to get more sophisticated, the later versions of VueRouter allow you to pass properties to routes in several ways.
Finally, there's always Vuex or some other state management tool if your application gets complex enough.
The problem is that when you refresh the page, the whole app reloads, which includes the get, which is asynchronous. The router figures out that it needs to render details, so that component loads, and calls getFriends, but the asynchronous get hasn't finished.
You could work around this by saving and pulling the Promise from the get, but Bert's answer is correct: the Vue Way is to send data as props, not to have children pull it from parents.

Categories