Home > Net >  How to update a variable from an asynchronous function?
How to update a variable from an asynchronous function?

Time:04-19

In my template, in a v-slot (which means users is not available in <script setup>), I have

<template v-slot:body-cell-assignedTo="props">
  <q-td :props="props">
    <div v-for="u in props.users" :key="u">{{u}}</div>
  </q-td>
</template>

This displays

john
mary

I can enrich this information by calling an API:

fetch('https://example.com/api/user/john')
  .then(r => r.json())
  .then(r => console.log(r))

This displays in the console John de Brown, 1262-1423.

My question: how to combine these two mechanisms? In other words, how to asynchronously update the value in {{}}?

I would need to do something like

<div v-for="u in props.users" :key="u">{{enrichFetchFunction(u)}}</div>

but it would need to be asynchronous, and yet somehow return a value.

EDIT: I will ultimately enrich the source data that is displayed in the v-slot. I would still be interested, though, if waiting for such an asynchronous function there (à la await) is doable in Vuie.

CodePudding user response:

I assume you are using Compositions API. See this playground

<script setup>
import { ref, onMounted } from 'vue'
const users = ref([])
onMounted(async() => {
  fetch('https://mocki.io/v1/67abcfb6-4f25-4513-b0f9-1eb6c4906413')
  .then(r => r.json())
  .then(r => users.value = r)
})
</script>

<template>
  <div v-for="u in users" :key="u">{{u}}</div>
</template>

CodePudding user response:

This is doable with Lifecycle hooks such as mounted(), yet you will need some sort of listener to react to the information being changed. here is an example that updates the values as soon as it is mounted and includes a button that will also update the values (you can run the code here in Vue SFC Playground):

<template>
  <div id="app">
    <h1 v-for="u in enrichedUsers" :key="u">{{ u }}</h1>
    <button @click="myAsyncFunction">
      update
    </button>
  </div>
</template>
<script>
// pseudo api
const fetchEnrichedAPI = function(user) {
  return new Promise( (resolve, reject) => {
    var enrichedUsers = []
    if (user.includes('john')) {
      enrichedUsers.push('John de Brown, 1262-1423')
    }
    if (user.includes('mary')){
      enrichedUsers.push('Mary de Purple, 1423-1262')
    }

    setTimeout(() => {
      resolve(enrichedUsers);
    }, 300);
  });
}

export default{
  data() {
    return {
      props : { users: ['john','mary'] },
      enrichedUsers: []
    }
  },
  
  mounted() {
    // when mounted run this async function
    this.myAsyncFunction()
  },

  methods: {
    async myAsyncFunction() {
      // call api passing the list of users
      await fetchEnrichedAPI(this.props.users)
        .then((data) => {
          // if api work
          this.enrichedUsers = data;
          return true;
        })
        .catch((e) => {
          // if the api doesn't work
          console.error(e);
          this.enrichedUsers = this.props.users;
        })
    }
  },
}
</script>

I am aware that this does not use props, but it does work. If you would like to expand this to use props you may be able to do this with computed properties or functions in the v-for. See this post for more info on that.

  • Related