Skip to content

Instantly share code, notes, and snippets.

@javisperez
Last active March 26, 2020 01:37
Show Gist options
  • Save javisperez/26e7bc828b075496c0e564dbb1462387 to your computer and use it in GitHub Desktop.
Save javisperez/26e7bc828b075496c0e564dbb1462387 to your computer and use it in GitHub Desktop.
[UPDATED] VueRouteData plugin for [email protected] and vue@1or2
/**
* Note: this is an updated version of the original plugin:
* https://gist.github.com/fnlctrl/1cf9da63493e0fe78181a4f4e2cc6f64
*
* VueRouteData plugin for [email protected] and vue@1or2,
* implemented according to https://github.com/vuejs/vue-router/issues/296#issuecomment-235481643
*
* This plugin looks for `$options.fetchRouteData`,
* and watches `$route` using `$options.fetchRouteData` as handler.
*
* Before `fetchRouteData` executes, this plugin sets 'loadingRouteData' to true,
* and when it finishes executing, the plugin sets 'loadingRouteData' to false,
* so `fetchRouteData` can either be normal functions or async functions.
* Note: you need to define `loadingRouteData` in component's data option to get this working.
*
* It also injects two helper functions, `$setAsyncData` and `$reloadRouteData`,
* for details see below.
*
* Usage: (babel and Promise polyfill required)
* import VueRouter from '...'
* import VueRouteData from '...'
* Vue.use(VueRouter).use(VueRouteData)
*
* Update: Added an internal Vue instance so it doesn't require
* the declaration of the "loadingData" variable in the component.
* Also, as the "loadingData" is a boolean type variable i've renamed it to "isLoadingData".
*
* Author: fnlCtrl([email protected])
* Updated by: Javis Perez <https://www.github.com/javisperez>
* License: MIT
*/
function install(Vue) {
if (install.installed) return;
install.installed = true;
let vm = new Vue({
data() {
return {
isLoadingRouteData: false
};
}
});
Vue.prototype.$routeData = vm;
const isVersion1 = Vue.version[0] === '1',
mixin = {
[isVersion1 ? 'init' : 'beforeCreate']() {
if (this.$options.fetchRouteData) {
!this.$options.methods && (this.$options.methods = {});
/**
* Utility method for setting async data (promises or then-ables) on an instance
* @param promises - {key: promise}
*/
this.$options.methods.$setAsyncData = promises => Promise.all(
Object
.keys(promises)
.map(key => Promise
.resolve(promises[key])
.then(val => Vue.set(this, key, val))
)
);
/**
* Utility method for reloading route data
*/
this.$options.methods.$reloadRouteData =
() => this.$options.fetchRouteData(this.$route);
}
},
created: initWatcher,
beforeDestroy: destroyWatcher,
/* Keep-alive support */
[isVersion1 ? 'attached' : 'activated']: initWatcher,
[isVersion1 ? 'detached' : 'deactivated']: destroyWatcher
};
Vue.mixin(mixin);
function initWatcher() {
if (this.$options.fetchRouteData && !this._unwatch$route) {
this._unwatch$route = this.$watch(
'$route',
function () {
this.$routeData.isLoadingRouteData = true;
var promise = this.$options.fetchRouteData.apply(this, arguments);
Promise.resolve(promise).then(() => this.$routeData.isLoadingRouteData = false);
},
{immediate: true}
);
}
}
}
function destroyWatcher() {
this._unwatch$route && this._unwatch$route();
this._unwatch$route = null;
}
export default {
install
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment