vue-async-computed
Advanced tools
Comparing version 3.3.1 to 3.4.0
@@ -5,2 +5,3 @@ <!-- START doctoc generated TOC please keep comment here to allow auto update --> | ||
- [v3.4.0](#v340) | ||
- [v3.3.0](#v330) | ||
@@ -23,2 +24,7 @@ - [v3.2.1](#v321) | ||
<!-- END doctoc generated TOC please keep comment here to allow auto update --> | ||
### v3.4.0 | ||
* Add a `shouldUpdate` option, which can control when and if | ||
an async computed property updates. | ||
### v3.3.0 | ||
@@ -25,0 +31,0 @@ * New feature: lazily computed properties. |
(function (global, factory) { | ||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : | ||
typeof define === 'function' && define.amd ? define(factory) : | ||
(global.AsyncComputed = factory()); | ||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : | ||
typeof define === 'function' && define.amd ? define(factory) : | ||
(global.AsyncComputed = factory()); | ||
}(this, (function () { 'use strict'; | ||
function isComputedLazy (item) { | ||
return item.hasOwnProperty('lazy') && item.lazy | ||
} | ||
function isComputedLazy (item) { | ||
return item.hasOwnProperty('lazy') && item.lazy | ||
} | ||
function isLazyActive (vm, key) { | ||
return vm[lazyActivePrefix + key] | ||
} | ||
function isLazyActive (vm, key) { | ||
return vm[lazyActivePrefix + key] | ||
} | ||
const lazyActivePrefix = 'async_computed$lazy_active$'; | ||
const lazyDataPrefix = 'async_computed$lazy_data$'; | ||
const lazyActivePrefix = 'async_computed$lazy_active$', | ||
lazyDataPrefix = 'async_computed$lazy_data$'; | ||
function initLazy (data, key) { | ||
data[lazyActivePrefix + key] = false; | ||
data[lazyDataPrefix + key] = null; | ||
} | ||
function initLazy (data, key) { | ||
data[lazyActivePrefix + key] = false; | ||
data[lazyDataPrefix + key] = null; | ||
} | ||
function makeLazyComputed (key) { | ||
return { | ||
get () { | ||
this[lazyActivePrefix + key] = true; | ||
return this[lazyDataPrefix + key] | ||
}, | ||
set (value) { | ||
this[lazyDataPrefix + key] = value; | ||
function makeLazyComputed (key) { | ||
return { | ||
get () { | ||
this[lazyActivePrefix + key] = true; | ||
return this[lazyDataPrefix + key] | ||
}, | ||
set (value) { | ||
this[lazyDataPrefix + key] = value; | ||
} | ||
} | ||
} | ||
} | ||
function silentSetLazy (vm, key, value) { | ||
vm[lazyDataPrefix + key] = value; | ||
} | ||
function silentGetLazy (vm, key) { | ||
return vm[lazyDataPrefix + key] | ||
} | ||
function silentSetLazy (vm, key, value) { | ||
vm[lazyDataPrefix + key] = value; | ||
} | ||
function silentGetLazy (vm, key) { | ||
return vm[lazyDataPrefix + key] | ||
} | ||
const prefix = '_async_computed$'; | ||
const prefix = '_async_computed$'; | ||
const DidNotUpdate = typeof Symbol === 'function' ? Symbol('did-not-update') : {}; | ||
const AsyncComputed = { | ||
install (Vue, pluginOptions) { | ||
pluginOptions = pluginOptions || {}; | ||
const AsyncComputed = { | ||
install (Vue, pluginOptions) { | ||
pluginOptions = pluginOptions || {}; | ||
Vue.config | ||
.optionMergeStrategies | ||
.asyncComputed = Vue.config.optionMergeStrategies.computed; | ||
Vue.config | ||
.optionMergeStrategies | ||
.asyncComputed = Vue.config.optionMergeStrategies.computed; | ||
Vue.mixin({ | ||
beforeCreate () { | ||
const optionData = this.$options.data; | ||
Vue.mixin({ | ||
beforeCreate () { | ||
const optionData = this.$options.data; | ||
if (!this.$options.computed) this.$options.computed = {}; | ||
if (!this.$options.computed) this.$options.computed = {}; | ||
for (const key in this.$options.asyncComputed || {}) { | ||
this.$options.computed[prefix + key] = getterFn(key, this.$options.asyncComputed[key]); | ||
} | ||
for (const key in this.$options.asyncComputed || {}) { | ||
this.$options.computed[prefix + key] = getterFn(key, this.$options.asyncComputed[key]); | ||
} | ||
this.$options.data = function vueAsyncComputedInjectedDataFn () { | ||
const data = ( | ||
(typeof optionData === 'function') | ||
? optionData.call(this) | ||
: optionData | ||
) || {}; | ||
this.$options.data = function vueAsyncComputedInjectedDataFn () { | ||
const data = ( | ||
(typeof optionData === 'function') | ||
? optionData.call(this) | ||
: optionData | ||
) || {}; | ||
for (const key in this.$options.asyncComputed || {}) { | ||
const item = this.$options.asyncComputed[key]; | ||
if (isComputedLazy(item)) { | ||
initLazy(data, key); | ||
this.$options.computed[key] = makeLazyComputed(key); | ||
} else { | ||
data[key] = null; | ||
} | ||
} | ||
return data | ||
}; | ||
}, | ||
created () { | ||
for (const key in this.$options.asyncComputed || {}) { | ||
const item = this.$options.asyncComputed[key]; | ||
const item = this.$options.asyncComputed[key], | ||
value = generateDefault.call(this, item, pluginOptions); | ||
if (isComputedLazy(item)) { | ||
initLazy(data, key); | ||
this.$options.computed[key] = makeLazyComputed(key); | ||
silentSetLazy(this, key, value); | ||
} else { | ||
data[key] = null; | ||
this[key] = value; | ||
} | ||
} | ||
return data | ||
}; | ||
}, | ||
created () { | ||
for (const key in this.$options.asyncComputed || {}) { | ||
const item = this.$options.asyncComputed[key], | ||
value = generateDefault.call(this, item, pluginOptions); | ||
if (isComputedLazy(item)) { | ||
silentSetLazy(this, key, value); | ||
} else { | ||
this[key] = value; | ||
} | ||
} | ||
for (const key in this.$options.asyncComputed || {}) { | ||
let promiseId = 0; | ||
this.$watch(prefix + key, newPromise => { | ||
const thisPromise = ++promiseId; | ||
for (const key in this.$options.asyncComputed || {}) { | ||
let promiseId = 0; | ||
this.$watch(prefix + key, newPromise => { | ||
const thisPromise = ++promiseId; | ||
if (!newPromise || !newPromise.then) { | ||
newPromise = Promise.resolve(newPromise); | ||
} | ||
if (newPromise === DidNotUpdate) { | ||
return | ||
} | ||
newPromise.then(value => { | ||
if (thisPromise !== promiseId) return | ||
this[key] = value; | ||
}).catch(err => { | ||
if (thisPromise !== promiseId) return | ||
if (!newPromise || !newPromise.then) { | ||
newPromise = Promise.resolve(newPromise); | ||
} | ||
if (pluginOptions.errorHandler === false) return | ||
newPromise.then(value => { | ||
if (thisPromise !== promiseId) return | ||
this[key] = value; | ||
}).catch(err => { | ||
if (thisPromise !== promiseId) return | ||
const handler = (pluginOptions.errorHandler === undefined) | ||
? console.error.bind(console, 'Error evaluating async computed property:') | ||
: pluginOptions.errorHandler; | ||
if (pluginOptions.errorHandler === false) return | ||
if (pluginOptions.useRawError) { | ||
handler(err); | ||
} else { | ||
handler(err.stack); | ||
} | ||
}); | ||
}, { immediate: true }); | ||
const handler = (pluginOptions.errorHandler === undefined) | ||
? console.error.bind(console, 'Error evaluating async computed property:') | ||
: pluginOptions.errorHandler; | ||
if (pluginOptions.useRawError) { | ||
handler(err); | ||
} else { | ||
handler(err.stack); | ||
} | ||
}); | ||
}, { immediate: true }); | ||
} | ||
} | ||
} | ||
}); | ||
} | ||
}; | ||
}); | ||
} | ||
}; | ||
function getterFn (key, fn) { | ||
if (typeof fn === 'function') return fn | ||
function getterFn (key, fn) { | ||
if (typeof fn === 'function') return fn | ||
let getter = fn.get; | ||
let getter = fn.get; | ||
if (fn.hasOwnProperty('watch')) { | ||
getter = function getter () { | ||
fn.watch.call(this); | ||
return fn.get.call(this) | ||
}; | ||
if (fn.hasOwnProperty('watch')) { | ||
const previousGetter = getter; | ||
getter = function getter () { | ||
fn.watch.call(this); | ||
return previousGetter.call(this) | ||
}; | ||
} | ||
if (fn.hasOwnProperty('shouldUpdate')) { | ||
const previousGetter = getter; | ||
getter = function getter () { | ||
if (fn.shouldUpdate.call(this)) { | ||
return previousGetter.call(this) | ||
} | ||
return DidNotUpdate | ||
}; | ||
} | ||
if (isComputedLazy(fn)) { | ||
const nonLazy = getter; | ||
getter = function lazyGetter () { | ||
if (isLazyActive(this, key)) { | ||
return nonLazy.call(this) | ||
} else { | ||
return silentGetLazy(this, key) | ||
} | ||
}; | ||
} | ||
return getter | ||
} | ||
if (isComputedLazy(fn)) { | ||
const nonLazy = getter; | ||
getter = function lazyGetter () { | ||
if (isLazyActive(this, key)) { | ||
return nonLazy.call(this) | ||
} else { | ||
return silentGetLazy(this, key) | ||
} | ||
}; | ||
} | ||
return getter | ||
} | ||
function generateDefault (fn, pluginOptions) { | ||
let defaultValue = null; | ||
function generateDefault (fn, pluginOptions) { | ||
let defaultValue = null; | ||
if ('default' in fn) { | ||
defaultValue = fn.default; | ||
} else if ('default' in pluginOptions) { | ||
defaultValue = pluginOptions.default; | ||
if ('default' in fn) { | ||
defaultValue = fn.default; | ||
} else if ('default' in pluginOptions) { | ||
defaultValue = pluginOptions.default; | ||
} | ||
if (typeof defaultValue === 'function') { | ||
return defaultValue.call(this) | ||
} else { | ||
return defaultValue | ||
} | ||
} | ||
if (typeof defaultValue === 'function') { | ||
return defaultValue.call(this) | ||
} else { | ||
return defaultValue | ||
/* istanbul ignore if */ | ||
if (typeof window !== 'undefined' && window.Vue) { | ||
// Auto install in dist mode | ||
window.Vue.use(AsyncComputed); | ||
} | ||
} | ||
/* istanbul ignore if */ | ||
if (typeof window !== 'undefined' && window.Vue) { | ||
// Auto install in dist mode | ||
window.Vue.use(AsyncComputed); | ||
} | ||
return AsyncComputed; | ||
return AsyncComputed; | ||
}))); |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; | ||
@@ -5,3 +7,3 @@ | ||
(typeof exports === 'undefined' ? 'undefined' : _typeof(exports)) === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : global.AsyncComputed = factory(); | ||
})(this, function () { | ||
})(undefined, function () { | ||
'use strict'; | ||
@@ -17,4 +19,4 @@ | ||
var lazyActivePrefix = 'async_computed$lazy_active$'; | ||
var lazyDataPrefix = 'async_computed$lazy_data$'; | ||
var lazyActivePrefix = 'async_computed$lazy_active$', | ||
lazyDataPrefix = 'async_computed$lazy_data$'; | ||
@@ -46,2 +48,3 @@ function initLazy(data, key) { | ||
var prefix = '_async_computed$'; | ||
var DidNotUpdate = typeof Symbol === 'function' ? Symbol('did-not-update') : {}; | ||
@@ -96,2 +99,6 @@ var AsyncComputed = { | ||
if (newPromise === DidNotUpdate) { | ||
return; | ||
} | ||
if (!newPromise || !newPromise.then) { | ||
@@ -134,7 +141,19 @@ newPromise = Promise.resolve(newPromise); | ||
if (fn.hasOwnProperty('watch')) { | ||
var previousGetter = getter; | ||
getter = function getter() { | ||
fn.watch.call(this); | ||
return fn.get.call(this); | ||
return previousGetter.call(this); | ||
}; | ||
} | ||
if (fn.hasOwnProperty('shouldUpdate')) { | ||
var _previousGetter = getter; | ||
getter = function getter() { | ||
if (fn.shouldUpdate.call(this)) { | ||
return _previousGetter.call(this); | ||
} | ||
return DidNotUpdate; | ||
}; | ||
} | ||
if (isComputedLazy(fn)) { | ||
@@ -141,0 +160,0 @@ var nonLazy = getter; |
{ | ||
"name": "vue-async-computed", | ||
"version": "3.3.1", | ||
"version": "3.4.0", | ||
"description": "Async computed properties for Vue", | ||
@@ -15,3 +15,3 @@ "main": "dist/vue-async-computed.js", | ||
"watch": "watch 'npm run build' src test", | ||
"test": "babel-node --presets es2015 test/index.js | tspec", | ||
"test": "babel-node --presets env test/index.js | tspec", | ||
"prebuild": "npm run check -s && npm run clean -s && mkdirp dist", | ||
@@ -54,24 +54,24 @@ "build": "npm run rollup -s && npm run babel -s", | ||
"babel-cli": "^6.26.0", | ||
"babel-core": "^6.26.0", | ||
"babel-eslint": "^7.2.3", | ||
"babel-core": "^6.26.3", | ||
"babel-eslint": "^8.2.5", | ||
"babel-istanbul": "^0.12.2", | ||
"babel-preset-es2015": "^6.24.1", | ||
"coveralls": "^2.13.1", | ||
"dependency-check": "^2.9.1", | ||
"doctoc": "^1.3.0", | ||
"eslint": "^4.5.0", | ||
"eslint-config-standard": "^10.2.1", | ||
"eslint-plugin-import": "^2.7.0", | ||
"eslint-plugin-node": "^5.1.1", | ||
"eslint-plugin-promise": "^3.5.0", | ||
"eslint-plugin-standard": "^3.0.1", | ||
"babel-preset-env": "^1.7.0", | ||
"coveralls": "^3.0.2", | ||
"dependency-check": "^3.1.0", | ||
"doctoc": "^1.3.1", | ||
"eslint": "^5.2.0", | ||
"eslint-config-standard": "^11.0.0", | ||
"eslint-plugin-import": "^2.13.0", | ||
"eslint-plugin-node": "^7.0.1", | ||
"eslint-plugin-promise": "^3.8.0", | ||
"eslint-plugin-standard": "^3.1.0", | ||
"estraverse-fb": "^1.3.2", | ||
"mkdirp": "^0.5.1", | ||
"rimraf": "^2.6.1", | ||
"rollup": "^0.48.2", | ||
"tap-spec": "^4.1.1", | ||
"tape": "^4.8.0", | ||
"vue": "^2.4.2", | ||
"rimraf": "^2.6.2", | ||
"rollup": "^0.63.4", | ||
"tap-spec": "^5.0.0", | ||
"tape": "^4.9.1", | ||
"vue": "^2.5.16", | ||
"watch": "^1.0.2" | ||
} | ||
} |
@@ -105,3 +105,3 @@ <big><h1 align="center">vue-async-computed</h1></big> | ||
--> | ||
<script src="https://unpkg.com/vue-async-computed@3.3.0"></script> | ||
<script src="https://unpkg.com/vue-async-computed@3.4.0"></script> | ||
```` | ||
@@ -267,2 +267,36 @@ | ||
### Conditional Recalculation | ||
Using `watch` it is possible to run the computed property again but it will run regardless of the | ||
value of the watched property. If you need more control over when the computation should be rerun | ||
you can use `shouldUpdate`: | ||
````js | ||
new Vue({ | ||
data: { | ||
postId: 1, | ||
// Imagine pageType can be one of 'index', 'details' and 'edit' | ||
pageType: 'index' | ||
}, | ||
asyncComputed: { | ||
blogPostContent: { | ||
get () { | ||
return Vue.http.get('/post/' + this.postId) | ||
.then(response => response.data.postContent) | ||
}, | ||
// Will update whenever the pageType or postId changes | ||
// but only if the pageType is not 'index' this way the | ||
// blogPostContent will be refetched when loading the | ||
// 'details' and 'edit' pages | ||
shouldUpdate () { | ||
return this.pageType !== 'index' | ||
} | ||
} | ||
} | ||
} | ||
```` | ||
The main advantage over adding an if statement within the get function is that when the computation is | ||
not rerun you are able to still access the old value. | ||
## Lazy properties | ||
@@ -269,0 +303,0 @@ |
28072
315
375