Skip to content

Feature request - lazy load #15

@thgh

Description

@thgh

I expected the computed getter to only fire when the getter is accessed. Do you think it's implementable as an option? { lazy: true }

I was able to implement the behaviour, but had to change a lot:

const prefix = 'async_computed$'

const AsyncComputed = {
  install (Vue, options) {
    options = options || {}

    Vue.config
      .optionMergeStrategies
      .asyncComputed = Vue.config.optionMergeStrategies.computed

    Vue.mixin({
      data () {
        if (this.$options.asyncComputed) {
          return {
            async_computed$: {}
          }
        }
        return {}
      },
      beforeCreate () {
        if (!this.$options.asyncComputed) {
          return
        }

        const optionComputed = this.$options.computed

        if (!this.$options.computed) this.$options.computed = {}

        const computed = (
            (typeof optionComputed === 'function')
              ? optionComputed.call(this)
              : optionComputed
           ) || {}

        // Add computed getter for each key
        Object.keys(this.$options.asyncComputed || {}).forEach(key => {
          computed[key] = function () {
            if (typeof this.$options.asyncComputed[key] !== 'function') {
              return this.$options.asyncComputed[key]
            }

            if (!this['_request$' + prefix + key]) {
              this['_request$' + prefix + key] = true

              // Call computed property
              this.$options.asyncComputed[key]()
                .then(value => {

                  // This will trigger watchers of the computed property
                  // because a default value was set in $data
                  this[prefix][key] = value

                  // Hacky way of allowing to trigger again
                  // Should use throttle-like function instead
                  setTimeout(() => {
                    this['_request$' + prefix + key] = true
                  }, 25)
                })
                .catch(err => {

                  // Error handler
                  const handler = (options.errorHandler === undefined)
                    ? console.error.bind(console, 'Error evaluating async computed property:')
                    : options.errorHandler

                  if (options.useRawError) {
                    handler(err)
                  } else {
                    handler(err.stack)
                  }
                })
            }

            // Return computed value
            return this[prefix][key]
          }
        })
        this.$options.computed = computed
      },
      created () {
        if (this.$options.asyncComputed) {

          // Set default value
          Object.keys(this.$options.asyncComputed || {}).forEach(key => {
            const fn = this.$options.asyncComputed[key], def = typeof fn.default === 'undefined' ? null : fn.default
            this.$set(this[prefix], key, typeof def === 'function' ? def.call(this) : def)
          })
        }
      }
    })
  }
}

export default AsyncComputed

// Auto install in dist mode
if (typeof window !== 'undefined' && window.Vue) {
  window.Vue.use(AsyncComputed)
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions