UNPKG

vue-async-everything

Version:

Vue Component Plugin for asynchronous data and computed properties.

129 lines (93 loc) 3.73 kB
import { debounce } from 'lodash' import { resolverForGivenFunction, dataObjBuilder, metaFunctionBuilder } from './core.js' import { globalDefaults, computedDefaults } from './defaults.js' export default function AsyncComputedMixinBuilder(options) { const globalOptions = globalDefaults(options) const meta = globalOptions.meta const metaCancel = metaFunctionBuilder('cancel', meta) const metaNow = metaFunctionBuilder('now', meta) const metaLoading = metaFunctionBuilder('loading', meta) const metaPending = metaFunctionBuilder('pending', meta) const metaError = metaFunctionBuilder('error', meta) const metaDefault = metaFunctionBuilder('default', meta) const metaDebounce = metaFunctionBuilder('debounce', meta) const metaResolver = metaFunctionBuilder('resolver', meta) const metaMore = metaFunctionBuilder('more', meta) const metaReset = metaFunctionBuilder('reset', meta) const metas = { metaPending, metaLoading, metaError, metaDefault, metaReset } const computedGlobalDefaults = computedDefaults(options) return { beforeCreate() { let properties = this.$options.asyncComputed || {} this.$options.methods = this.$options.methods let methods = this.$options.methods || {} for (const [propName, prop] of Object.entries(properties)) { const opt = computedDefaults(prop, computedGlobalDefaults) if (!opt.get) throw `An asyncComputed was created without a get method: ${opt}` let resolverFunction = resolverForGivenFunction.call(this, propName, metas, opt.get, opt.default, opt.transform, opt.error) if (opt.debounce !== false) { const debouncedResolverFunction = debounce( resolverFunction, opt.debounce.wait, opt.debounce.options ) // inject the $cancel and $now const pendingName = metaPending(propName) methods[metaCancel(propName)] = function() { this[pendingName] = false debouncedResolverFunction.cancel() } methods[metaNow(propName)] = function() { this[pendingName] = false debouncedResolverFunction.flush() } this[metaDebounce(propName)] = debouncedResolverFunction } this[metaResolver(propName)] = resolverFunction // load more stuff if (opt.more) { methods[metaMore(propName)] = resolverForGivenFunction.call(this, propName, metas, opt.more.get, opt.default, opt.transform, opt.error, opt.more.concat) } } }, beforeMount() { const properties = this.$options.asyncComputed || {} for (const [propName, prop] of Object.entries(properties)) { const opt = computedDefaults(prop, computedGlobalDefaults) if (!opt.watch && !opt.watchClosely) throw `A computed was created without any kind of watch: ${opt}` const resolverFunction = this[metaResolver(propName)] // get the debounced version of it const debouncedResolverFunction = this[metaDebounce(propName)] let hasRun = false const eager = opt.eager const shouldDebounce = !(opt.debounce === false || !opt.watch) const defaultWatch = opt.watch || opt.watchClosely this.$watch(defaultWatch, function() { if (eager && !hasRun) { hasRun = true resolverFunction() } else if (shouldDebounce) { this[metaPending(propName)] = true debouncedResolverFunction() } else { resolverFunction() } }, { deep: true, immediate: eager }) // if there's no debouncing set up, then watchClosely is ignored if (shouldDebounce && opt.watchClosely) { this.$watch(opt.watchClosely, function() { this[metaPending(propName)] = false debouncedResolverFunction.cancel() resolverFunction() }, { deep: true, immediate: false }) } } }, data() { return dataObjBuilder(this.$options.asyncComputed, metas, true) } } }