'Vue.js, How to check v-if directive with the results of an asynchronous function
I am showing to users, a web app which has links to another website. Depending on which link the user clicks on, it will take them to another page or stay on the same page.
My current implementation approach is to have a "v-if" directive that checks the results of an async function, but the value of the function always returns "Promise pending" and not the actual value.
I am trying to do something like
<router-link v-else-if="checkValue(origin.link)" target="_blank" :to= "origin/link" >
<span @click="checkValue(origin.link)">
{{ origin.value }}
</span>
</router-link>
the issue here is that "checkValue" in the v-if is an promise, so it never gets the true or false value, in the v-if.
I cannot store the data of this call in an data variable because there is millions and millions of records, and I can't store all of them. "checkValue" is an asynchronous function like so
async checkValue(link: string) {
const val = await axios.get('service/${link}')
if(val) {
return true
} else {
return false
}
Is there a way in the v-if directive, that I can check the return of this asynchronous function? Or Is there another approach I can do to solve this? thank you
Solution 1:[1]
If I were you I would use the v-if (or v-show) directive with a variable. I haven't tested the snippet below, but something like this should work:
try{
let response = await axios.get('service/${link}')
this.useThisVariableInVIF = true // or response.data.message;
}catch(error) {
this.useThisVariableInVIF = false;
console.log(error);
};
}
Then just v-else-if="useThisVariableInVIF"
Solution 2:[2]
A pending promise is a Proxy, which is, basically, an object. v-if checks for truthiness (which means it casts to boolean). In JavaScript, all objects are truthy.
This means that Boolean(someFunction()) (which is what v-if evaluates) will evaluate to true until the promise settles. After it settles, it will evaluate the truthiness of the result.
Here's how your problem is typically solved in Vue:
- create a boolean property. Let's name it:
isLoading. Declare it inside the object returned bydata, so it's reactive.
data: () => ({
isLoading: true,
orgin: {}
})
Now use your async method and, in the response, set isLoading to true while loading and then to false, when the promise resolved. Note you need to set this.isLoading = false in both cases of the Promise (fulfill/reject) regardless of how you handle errors (if you handle them).
methods: {
checkValue(link: string) {
this.isLoading = true;
this.origin = await axios.get('service/${link}');
this.isLoading = false;
}
}
your template tag should look along these lines:
<router-link v-else-if="origin.link && !isLoading" :to="origin.link">
<span v-text="origin.value" />
</router-link>
If you're using Composition API, the syntax is slightly different, but the logic is the same. Also note that in Vue3, there is a dedicated component for solving this type of problem: <suspense>. It allows specifying a template for when loading and one for when loaded.
Solution 3:[3]
you need not store the data of this call in an data variable,you can modify your code like this.
<router-link v-else-if="hasValue" target="_blank" :to= "origin/link" >
<span @click="checkValue(origin.link)">
{{ origin.value }}
</span>
</router-link>
<script>
export default {
data: function {
return {
hasValue: false
}
}
created: function() {
axios.get('service/${link}').then(c => {
this.hasValue = !!c
})
}
}
</script>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | |
| Solution 3 | allen |
