Use API call in component - vue.js

I am playing around with VueJS and trying to make an api call from within a component:
var postView = {
props: ['post'],
template: '<li>{{ post.title }}</li>',
url: 'https://jsonplaceholder.typicode.com/posts',
data: function () {
return {
results: []
}
},
mounted() {
axios.get(url).then(response => {
this.results = response.data
})
},
ready: function () { },
methods: {}
}
Vue.component('postitem', postView);
var app = new Vue({
el: '#app',
data: {},
ready: function () { },
methods: {}
})
I get the following error:
[Vue warn]: Property or method "results" is not defined on the
instance but referenced during render.
I am wondering what the best approach is to make api calls from within a component and display it on a HTML page. I learned that a component’s data option must be a function, but I'm not sure what the error related to 'results' means.

First of all you should consider using vue single file components. They are great for splitting your functionality.
Vue requests guide
You can watch the whole playlist for complete vue guide. The link is to the video that explains api calls in vue.

i think that error for (this)
you can do like that:
var vm = this;
axios.get(url).then(response => {
vm.results = response.data
})

Related

Error showing when call a function from method in $root.on in Vue

I need to call a method when dropdown value changes. Dropdown is in completely separate component from where i want to call a method. So i am using $root.
Trading.vue
<v-autocomplete
label="Entity"
v-model="tradingAs"
:items="getTradeEntities"
item-value="id"
item-text="entity"
hide-details
return-object
#change="tradeChange"
/>
tradeChange(){
this.$root.$emit('trade_as_event', this.tradingAs.id)
}
New.vue
data: () => ({
tradeAsAccount: null
}),
mounted: function(){
this.$root.$on('trade_as_event', function(data) {
this.tradeAsAccount = data
console.log(this.tradeAsAccount)
this.createQuoteConfig() //this line gives error
})
},
methods: {
createQuoteConfig() {
console.log('call api with updated id', this.tradeAsAccount)
}
}
Error:
Vue warn]: Error in event handler for "trade_as_event": "TypeError: this.createQuoteConfig is not a function"
(found in )
this in the anonymous function does not point to instance of current component. Actually it points to the $root.
mounted: function() {
const root = this.$root
this.$root.$on('trade_as_event', function(data) {
console.log(this===root); // true
})
}
There are two ways to solve the problem.
Option one: Arrow Function
In arrow functions, this retains the value of the enclosing lexical context's this.
this.$root.$on('trade_as_event', (data) => {
this.tradeAsAccount = data
console.log(this.tradeAsAccount)
this.createQuoteConfig()
})
Option two: Vue methods
All methods declared in Vue options will have their this context automatically bound to the Vue instance.
data: () => ({
tradeAsAccount: null
}),
mounted: function(){
this.$root.$on('trade_as_event', this.handleTradeAsEvent)
},
methods: {
handleTradeAsEvent(data) {
this.tradeAsAccount = data
console.log(this.tradeAsAccount)
this.createQuoteConfig()
},
createQuoteConfig() {
console.log('call api with updated id', this.tradeAsAccount)
}
}

Dynamic render function in Vue instance based on authentication check

I'm adding JWT authentication to my Vue app and I have my Login.vue and App.vue seperated which means that I don't want to render the App.vue when the user is not logged in.
new Vue({
router,
render: function (app) {
if (this.$auth.check()) {
return app(App);
} else {
return app(Login);
}
}
}).$mount('#app')
This works but since
this.$auth.check()
Takes a second to load you see the Login app being rendered for a second and then it switches to the App. How can I fix this? I think I should use await but I can't get it to work properly.
How can I fix this? I think I should use await but I can't get it to work properly.
It depends on what is this.$auth.check() return. If it returns a promise, the answer is yes you should use await.
But unfortunately render function must be synchronous. What you can do is use one more wrapper component.
new Vue({
render(createElement) {
return createElement({
data: () => ({
component: null
}),
async created() {
this.component = await checkAuth() ? App : Login
},
render(createElement) {
return createElement(this.component)
}
})
}
}).$mount('#app')
Demo
Note:
I would prefer to create a wrapper component as single-file component.
It seems you are using vue-router you might consider to use Navigation Guards instead.
Update
As you may be already notice you have no need a wrapper component at all.
new Vue({
data: () => ({
component: null
}),
async created() {
this.component = await checkAuth() ? App : Login
},
render(createElement) {
return createElement(this.component)
}
}).$mount('#app')

The prop object's property is undefined in refresh function

I use Vue.js and have a component. I pass a prop "request" to that component:
<adjustments-list
v-if="request"
:request="request"
/>
In the component I'm able to do this:
<text-input
:value="request.id"
/>
It works that is the value of "id" is displayed.
In props section of component:
props: {
request: Object
In mounted hook of component:
async mounted () {
await this.refresh()
},
In refresh function of component:
async refresh () {
console.log('this.request.id =', this.request.id)
if (this.request.id) {
const data = await requestApi.getRequestResultAdjustmentByReqId(this.request.id)
}
},
The this.request.id is undefined.
I'm not sure why.
If the request property is asynchronously available to the component then, you have to use combination of watchers like:
// adjustments-list component
new Vue({
props: {
request: Object
},
data() {
return {
apiData: null
}
},
watch: {
request(newValue, _oldValue) {
this.refresh(newValue);
}
},
mounted: function () {
// Do something here
},
methods: {
refresh (request) {
if (request.id) {
// Using promise instead of async-await
requestApi.getRequestResultAdjustmentByReqId(request.id)
.then(() => this.apiData = data);
}
}
}
});
Also, note that, mounted should be a plain old JS function and not an async function. That's the lifecycle method of the component supposed to behave in particular way.

VueJS loading data from AJAX call and passing it to child components without v-if

I am loading data in root Vue instance using ajax and trying to pass it to child components. And I am getting undefined data. Of course, It is happening becasue of Async nature of ajax call so my question is how to do it without render blocking the child components using v-if. What is best practice to do it.
Here is my demo app -
https://codepen.io/xblack/pen/jXQeWv?editors=1010
Vue.component('child-one',{
template:'#child-one',
props:['mydataOne']
});
Vue.component('child-two',{
template:'#child-two',
props:['mydataTwo']
});
let app = new Vue({
el:'#app',
data:{
welcome:'Hello World',
mydata:null
},
methods:{
getdataApi:function(){
var self = this;
$.getJSON( "https://jsonplaceholder.typicode.com/users", function( data ) {
self.mydata = data;
});
}
},
created:function(){
this.getdataApi();
},
mounted:function(){
this.getdataApi();
console.log('api data->',this.mydata);
}
});
Here is the main reason:
https://stackoverflow.com/a/54163297/523630
Your mydataOne and mydataTwo properties should be mydata-one and mydata-two in component's html snippet, like so:
<div :mydata-one="mydata"></div>
Here is a working snipet of your code:
https://codepen.io/anon/pen/Jwewde?editors=1010
Vue.component('child-one',{
template:'#child-one',
props:['one']
});
Vue.component('child-two',{
template:'#child-two',
props:['two']
});
let app = new Vue({
el:'#app',
data:{
welcome:'Hello World',
mydata:null
},
methods:{
getdataApi(){
$.getJSON( "https://jsonplaceholder.typicode.com/users", (data) => {
this.mydata = data;
});
}
},
mounted:function(){
this.getdataApi();
}
});
Here you can read about loading JSON data in Vue using axios:
https://v2.vuejs.org/v2/cookbook/using-axios-to-consume-apis.html

Call Vue method on button click

I am new to Vue and I've been toying around with a basic component and trying to get some interactivity to work. However, when attempting to implement some methods, I find that nothing actually happens. My code looks like this:
var testComponent = Vue.component('testComponent', {
data: function () {},
props: [ 'maps' ],
methods: {
filt: function() {
alert("Useful alert");
}
},
template: "<div><button class='btn-primary' #click='filt'>Filter</button></div>"
});
var vm = new Vue({
el: '#app',
data: {},
methods: {},
computed: {},
components: {
TestComponent: testComponent
},
ready: function () {}
});
And my HTML essentially contains only this:
<test-component></test-component>
I would like to call the testComponent's filt method (which will later hopefully become a working filter method for the maps prop), but the button gives no alert on pressing it.
I've tried a few variations like v-on:click, but to no avail.
Any help would be greatly appreciated!