Skip to content

Instantly share code, notes, and snippets.

@boukeversteegh
Last active February 2, 2022 23:07
Show Gist options
  • Save boukeversteegh/3de2d12f6c1a3f5a5ef4d428cbd9a163 to your computer and use it in GitHub Desktop.
Save boukeversteegh/3de2d12f6c1a3f5a5ef4d428cbd9a163 to your computer and use it in GitHub Desktop.
Async getters for vue
<template>
<input v-model="query"/>
<ul>
<li v-for="user in users" :key="user.name">{{ user.name }}</li>
</ul>
</template>
<script lang="ts">
@Component({})
export default class ExampleComponent extends Vue {
query = 'john'
@Async({ default: [] })
get users(): {name: string}[] {
// You can call async functions within your getters, by decorating the getter with @Async()
return async(searchAsync(this.query, true))
}
get userCount() {
// The async property is useable, as if it was a normal property.
return this.users.length
}
@Async()
get exampleWithAwait() {
return async(async () => {
var message = await this.someMessageAsync();
return message.length;
});
}
async someMessageAsync() {
return "Hello world";
}
}
</script>
// Some fake data and fake async endpoint
const userData = [
{
name: 'John Doe',
email: 'info@example.com',
},
{
name: 'Jane Doe',
email: 'jane@example.com',
},
]
export function searchAsync(query: string, caseSensitive: boolean): Promise<User[]> {
return new Promise((resolve) => {
setTimeout(() => {
resolve(
userData.filter((user) => user.name.toLowerCase().indexOf(query?.toLowerCase()) > -1)
)
}, 500)
})
}
/**
* VueJS calculated properties that return a Promise
*/
// @Async() decorator
export function Async(asyncOptions: { default: any }) {
return createDecorator((options, property) => {
// Define a new reactive property on the Vue instance
options.data = () => ({ [property]: asyncOptions?.default })
// Move the async property to *Async
const asyncProperty = `${property}Async`
options.computed[asyncProperty] = options.computed[property]
// Watch changes to the async property
options.watch = {
[asyncProperty]: {
immediate: true,
handler: function (val, oldVal) {
// The promise changed, so listen to it.
val.then((value) => {
// Write the value to the reactive property
console.log('resolved', value)
this[property] = value
return value
})
},
},
}
/* eslint-disable fp/no-delete */
delete options.computed[property]
})
}
// async helper method
export function asyncComputed<T>(promise: Promise<T> | (() => Promise<T>)): T {
return (typeof promise === 'function' ? promise() : promise) as any
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment