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 of data to this.topGameImageURL only seems to work within the scope of the then(...)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 inside GetTopGameImageURL, 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 a v-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 output

    Still 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 directly infoBlocks in the mounted()?
    like

     this.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.


Log in to reply