Skip to content

Instantly share code, notes, and snippets.

@fnlctrl
Last active July 21, 2020 21:30
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save fnlctrl/1cf9da63493e0fe78181a4f4e2cc6f64 to your computer and use it in GitHub Desktop.
Save fnlctrl/1cf9da63493e0fe78181a4f4e2cc6f64 to your computer and use it in GitHub Desktop.
VueRouteData plugin for vue-router@2.0 and vue@1or2
/**
* VueRouteData plugin for vue-router@2.0 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)
*
* Author: fnlCtrl(fnlctrl@gmail.com)
* License: MIT
*/
function install(Vue) {
if (install.installed) return;
install.installed = true;
const isVersion1 = Vue.version[0] == '1';
const 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 () {
Vue.set(this, 'loadingRouteData', true);
var promise = this.$options.fetchRouteData.apply(this, arguments);
Promise.resolve(promise).then(() => Vue.set(this, 'loadingRouteData', false));
},
{immediate: true}
);
}
}
}
function destroyWatcher() {
this._unwatch$route && this._unwatch$route();
this._unwatch$route = null;
}
export default {
install
}
@javisperez
Copy link

Hey man thx for this :) is just what i needed 👍

I've made an update to your original plugin, i hope you don't mind. Here's my updated version:
https://gist.github.com/javisperez/26e7bc828b075496c0e564dbb1462387

My update just adds an internal Vue instance with a data property for the "loadingData" variable, so is not required to declare it first, instead it just refer to the internal vue instance as "$routeData" and variable would be like:

this.$routeData.isLoadingData

(oh yes, also i renamed it as is a boolean and makes a little more sense to me :) ).

Great work man, thank you again 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment