Calling API in method and getting [object Promise] - vue.js

I'm using Nuxt.js in static site mode, and trying to get an image from an API using a string passed in a prop, however, in the template I am getting [object Promise]. I would've thought that return before the get request would resolve the promise, but I think my grasp of promises and Nuxt.js a little off. Any help would be greatly appreciated.
<template>
<div>
{{ getThumbnailSrc() }}
</div>
</template>
<script>
import axios from 'axios'
export default {
props: {
link: {
type: String,
required: true
}
},
data() {
return {
imageUrl: null
}
},
methods: {
getVimeoId(link) {
return link.split('/').pop()
},
getThumbnailSrc() {
return axios
.get(
`https://vimeo.com/api/v2/video/${this.getVimeoId(
this.link
)}.json`
)
.then(response => {
const vimeoThumbnailUrl = response.data[0].thumbnail_large
console.log(vimeoThumbnailUrl)
return {
vimeoThumbnailUrl
}
})
.catch(error => {
console.log(error)
})
}
}
}
</script>

It sure won't! XHR requests are asynchronous and therefore the template has no idea that it needs to wait.
Solve it by using an additional data property on the component, and using that instead:
data() {
return {
imageUrl: null,
thumbnailSrc: null
}
},
And in your callback:
.then(response => {
const vimeoThumbnailUrl = response.data[0].thumbnail_large
console.log(vimeoThumbnailUrl)
this.thumbnailSrc = vimeoThumbnailUrl
})
Now you can use {{thumbnailSrc}} and it will load appropriately.

Related

Why action of Vuex returns a promise<pending>?

I have an action in Vuex actions which commit a mutation that it take a payload from the component, that is a number of the index for returning an object, it works fine on Vuex js file meaning that shows the selected item on the console, as I said it gets index from the payload,
but on the component, it gives me Promise <Pending>, why that's happening? for now, I do not use any API for my Nuxt/Vue app, but I will, and for now, I just want to know why this is happening and what is the best solution for solving this
Here my Vuex codes:
export const state = () => ({
articles: [
{
uid: 0,
img: 'https://raw.githubusercontent.com/muhammederdem/mini-player/master/img/1.jpg',
link: '/articles/1',
},
{
uid: 1,
img: 'https://raw.githubusercontent.com/muhammederdem/mini-player/master/img/2.jpg',
link: '/articles/2',
},
],
})
export const getters = {
getArticles(state) {
return state.articles
},
}
export const mutations = {
getSpeceficArticle(state, payload) {
return state.articles[payload]
},
}
export const actions = {
getSpeceficArticle({ commit }, payload) {
commit('getSpeceficArticle', payload)
},
}
and here my component codes:
<template>
<div class="article">
{{ getSpeceficArticle() }}
<div class="article__banner">
<img src="" alt="" />
</div>
<div class="article__text">
<p></p>
</div>
</div>
</template>
<script>
export default {
name: 'HomeArticlesArticle',
data() {
return {
item: '',
}
},
// computed: {},
methods: {
async getSpeceficArticle() {
return await this.$store.dispatch('articles/getSpeceficArticle', 0)
},
},
}
</script>
actions are used to update the state they are like mutations but the main difference between them is that actions can include some asynchronous tasks, if you want to get a specific article at given index you should use a getter named getArticleByIndex :
export const getters = {
getArticles(state) {
return state.articles
},
getArticleByIndex:: (state) => (index) => {
return state.articles[index]
}
}
then define a computed property called articleByIndex :
<script>
export default {
name: 'HomeArticlesArticle',
data() {
return {
item: '',
}
},
computed: {
articleByIndex(){
return this.$store.getters.articles.getArticleByIndex(0)
}
},
methods: {
},
}
</script>
#Mohammad if you find yourself using a lot of getters/actions etc from Vuex and they're starting to get a little wordy, you can bring in mapGetters from Vuex and rename your calls to something a little more convenient. So your script would become,
<script>
import { mapGetters } from 'vuex'
export default {
name: 'HomeArticlesArticle',
data() {
return {
item: '',
}
},
computed: {
articleByIndex(){
return this.getArticleByIndex(0)
}
},
methods: {
...mapGetters({
getArticleByIndex: 'articles/getArticleByIndex',
})
},
}
</script>
You can add ...mapGetters, ...mapActions to your computed section also.
since there is no web service call in vuex action, try to remove async and await keywords from the component.
Later when you add a webservice call than you can wrap action body in new Promise with resolve and reject and then you can use async and await in component. let me know if this works for you.

Vuex: Data sometimes gets 'undefined' during hard refresh

I am using Vuex for the first time and I have this occasional problem in console:
Error: TypeError: Cannot read property 'name' of undefined
Info: render
Any idea on how I can fix this problem?
Here is my setup:
In Vuex (store.js) I have a getter like so:
state: {
statuses: []
},
actions: {
async fetchStatuses({ commit }) {
try {
const response = await ApiService.getStatusFlags()
commit('SET_STATUSES', response.data)
} catch (err) {
console.error(err)
}
}
},
getters: {
getStatusById: state => id => {
return state.statuses.find(status => status.id === id)
},
...snip...
And on the page where I am calling this getter is like so:
IssueDetail.vue template:
<span class="badge badge-success">{{ getStatusById(issue.status).name }}</span>
IssueDetail.vue script section:
import { mapGetters } from 'vuex'
export default {
name: 'IssueDetail',
data() {
return {
isBusy: true,
issue_id: this.$route.params.id,
issue: ''
}
},
async created() {
await this.getIssue()
this.isBusy = false
},
methods: {
async getIssue() {
try {
this.issue = (await ApiService.getIssue(this.$route.params.id)).data[0]
} catch (error) {
console.error(error)
}
}
},
computed: {
...mapGetters(['getStatusById'])
}
this
getStatusById(issue.status).name
cannot work with your default value of the issue prop. Either change your default value or change getStatusById so it can accept null or undefined as an input param OR change your expression in a template to something like:
issue.status? getStatusById(issue.status).name : ''

Unable to push json to data in vue.js

When I am using the below code with mounted function then it's perfectly pushing the data to "infox"
<script>
export default {
data() {
return {
infox: null,
dino: d_var
}
},
mounted() {
axios
.get(this.dino)
.then(response => (this.infox = response.data))
}
}
</script>
But when I am trying to convert the code to use method function as shown below then I am unable to get any data. Is it something I am doing wrong ?
<template>
<button v-on:click="loadmore" class="fluid ui button">Load More</button>
</template>
<script>
export default {
data() {
return {
infox: null,
dino: d_var
}
},
methods: {
loadmore: function(){
axios.get(this.dino)
.then(response => this.infox = response.data)
}
}
}
</script>
infox is set to null you should set it to array.
infox: []

How to use Axios with Vue-Multiselect?

New to using Vue-Multiselect. I am using axios to do a GET request from a JSON placeholder to test.
How do I get the title and post id to show up in my drop down?
Right now, I just get [Object Object] - [title] shown in my select box.
<!-- Vue component -->
<template>
<div>
<multiselect v-model='value' :options='posts' :custom-label='postWithTitle' placeholder='Select one' label='title' track-by='id'></multiselect>
{{ value }}
</div>
</template>
<script>
import Multiselect from "vue-multiselect";
import axios from "axios";
export default {
// OR register locally
components: { Multiselect },
data() {
return {
value: null,
posts: []
};
},
created() {
this.getPosts();
},
methods: {
getPosts() {
axios
.get("https://jsonplaceholder.typicode.com/posts")
.then(response => {
// eslint-disable-next-line
console.log(response);
this.posts = response.data;
})
.catch(error => {
// eslint-disable-next-line
console.log(error);
});
},
postWithTitle(id, title) {
return `${id} - [${title}]`;
}
}
};
</script>
fix:
postWithTitle(option) {
return `${option.id} - [${option.title}]`;
}
explaination:
i saw that when i simply console.logged inside the postWithTitle function:
the custom custom-label attribute was accepting a callback that only accepts one argument. that argument was the entire option object- a single entry of your posts array.

Printing data variable

I am trying to print data() variable. I am not getting output in HTML template.
<template>
<h3>{{app_skills}}</h3> <!-- I am not getting value here -->
</template>
<script>
export default {
name: "leftbar",
data() {
return {
app_skills: '',
}
},
methods : {
fetchskills (url) {
url = '/skills';
axios.get(url)
.then(response => {
this.app_skills = response.data.skills;
console.log(this.app_skills) // I am getting value here
})
.catch(error => {
console.log(error);
});
}
},
mounted() {
this.fetchskills();
}
}
</script>
Your code worked exactly as expected when I tried it (with a few environment-related changes):
<template>
<h3>{{app_skills}}</h3> <!-- I am not getting value here -->
</template>
<script>
import axios from 'axios';
export default {
name: "leftbar",
data() {
return {
app_skills: '',
}
},
methods : {
fetchskills (url) {
url = 'https://dns.google.com/resolve?name=example.com';
axios.get(url)
.then(response => {
this.app_skills = response.data;
console.log(this.app_skills) // I am getting value here
})
.catch(error => {
console.log(error);
});
}
},
mounted() {
this.fetchskills();
}
}
</script>
All I changed was including the axios library, changing the URL to pull from, and changing the response.data key to pull. It all works as expected. Perhaps you have an issue somewhere else in your surrounding code?