Promise puzzlement...
-
Hi all
I have this async function:
export async function getTopGameImageURL () { const twitch = connect() const optionalParams = { limit: 1 } const topGames = await twitch.getTopGames(optionalParams) const gameName = topGames.top[0].game.name const gameInfo = await twitch.searchGames(gameName) const url = gameInfo.games[0].box.medium return url }
which retrieves some data from Twitch. It all works well so far.
On the caller side, I do the following in ‘mounted’:
mounted () { // This allows you to do stuff 'on page load' twLib.getTopGameImageURL().then(data => { this.topGameImageURL = data }) console.log('URL Index: ' + this.topGameImageURL) ...
My issue is that the
console.log
shows an empty string, i.e. the assignment ofdata
tothis.topGameImageURL
only seems to work within the scope of thethen(...)
function.The URL should be available to a VUE page (q-img widget).
How do I make the value (data) available to the caller outside of the scope of
then()
?Cheers,
Michael -
@mboeni your operation is async, your console.log is executed before it is resolves, so you need to await that, or move your console.log inside your
then
. -
@metalsadman Okay, how would this look? I can’t use await outside an async function as far as I am aware of, so the
await
would only work insideGetTopGameImageURL
, but not in the actual mounted() function of the vue file…Assuming at some point in time
topGameImageURL
is updated with the URL. How would I properly make that work in the vue file anyway? I have done av-if
to only show the image if the url is not empty, but it never updates… -
you can make mounted async .
async mounted () ...
-
Okay, I’ve made a little bit of progress: Adding a watcher actually shows that the promise is resolved eventually:
watch: { topGameImageURL: function () { console.log('Image URL: ' + this.topGameImageURL) } }
Now I just need to figure out why the image is not displayed…
-
as @metalsadman said, make your mounted async.
async mounted () { // This allows you to do stuff 'on page load' this.topGameImageURL = await twLib.getTopGameImageURL() console.log('URL Index: ' + this.topGameImageURL) }
-
@metalsadman @jraez Yep that works.
console.log(..)
now shows the expected outputStill the image URL is not updated in the q-img widget. I am doing this:
data () { return { thumbStyle: { right: '4px', borderRadius: '5px', background: 'white', width: '7px', opacity: 0.7 }, contentStyle: { background: 'sedondary' }, // used when cursor is NOT over chat area contentActiveStyle: { background: 'secondary' }, // used when cursor IS over chat area localTextColor1: '', localTextColor2: '', topGameImageURL: '', infoBlocks: [ { id: this.createUUID(), image: this.topGameImageURL, title: 'Top Game: ', text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.' }, { id: this.createUUID(), image: '', title: '', text: '' }, { id: this.createUUID(), image: '', title: '', text: '' }, { id: this.createUUID(), image: '', title: '', text: '' }, { id: this.createUUID(), image: '', title: '', text: '' }, { id: this.createUUID(), image: '', title: '', text: '' } ] } }
on the data side ant this:
<q-img :src='infoBlock.image' basic :ratio="1.5" > <div class="absolute-bottom text-h6"> {{infoBlock.title}} </div> </q-img>
to display the image. It is probably a timing issue but I was assuming that vars in the
data
scope are updated per tick…Any ideas on this?
-
Do you have a loop or something? You don’t have infoBlock in your data.
-
Yep, sorry, it’s in a v-for:
<q-card v-for='infoBlock in infoBlocks' v-bind:key='infoBlock.id' class="col q-ma-sm tileBGColor" style="border-radius: 7px; height: 300px; width: 300px; min-width: 300px; max-width: 300px"> <div v-if="infoBlock.title.length > 3"> <q-img :src='infoBlock.image' basic :ratio="1.5" > <div class="absolute-bottom text-h6"> {{infoBlock.title}} </div> </q-img> <q-card-section class="q-gutter-xs"> {{infoBlock.text}} </q-card-section> </div> </q-card>
-
I never use self-reference in Vue component data, I’m not 100% sure it works as you expect (but I’m maybe wrong).
Why not feed directlyinfoBlocks
in themounted()
?
likethis.infoBlocks[0].image = await twLib.getTopGameImageURL()
or if you have reactivity issue, something like that:
this.$set(this.infoBlocks[0], 'image', await twLib.getTopGameImageURL())
-
@jraez Yep, that’s what I opted for…it works now as it should
Thanks a lot for your help @jraez and @metalsadman !
Cheers,
M.