Skip to content

Instantly share code, notes, and snippets.

@innocenzi
Last active March 30, 2022 08:51
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save innocenzi/bac9a14ff7611cc8bec713955b413c95 to your computer and use it in GitHub Desktop.
Save innocenzi/bac9a14ff7611cc8bec713955b413c95 to your computer and use it in GitHub Desktop.
Inertia route guards
<template>
<!-- ... -->
</template>
<script>
export default {
// ...
beforeRouteLeave (vm, options, event) {
// vm will now refer to this component instead of the link
return window.confirm(vm.$trans('ticket.confirm_leave_creation'));
},
afterRouteLeave(vm, options, event, visit) {
console.log(`You navigated to ${location.href}`);
}
}
</script>
import Vue from 'vue';
import { InertiaApp } from '@inertiajs/inertia-vue';
import RegisterRouteGuard from '@/Adapters/router-guard';
RegisterRouteGuard(Vue);
const app = document.getElementById('app');
new Vue({
render: h => h(InertiaApp, {
props: {
initialPage: JSON.parse(app.dataset.page),
resolveComponent: name => import(`@/View/${name}`)
.then(module => module.default)
.catch(message => console.error(message))
},
})
}).$mount(app)
// @ts-ignore
import Link from '@/Components/UI/Link';
import Vue, { VueConstructor } from 'vue';
declare global {
interface Window {
routerGuards: RouterGuards;
}
}
type BeforeRouteLeaveGuard = (vm: Vue, options: any, event: MouseEvent) => any;
type AfterRouteLeaveGuard = (vm: Vue, options: any, event: MouseEvent, visit?: Promise<any>) => any;
type Guard = BeforeRouteLeaveGuard | AfterRouteLeaveGuard;
type RouterGuards = { [key in GuardName]?: RouterGuardObject };
type GuardName = 'beforeRouteLeave' | 'afterRouteLeave';
interface RouterGuardObject {
component: Vue;
call: Guard;
}
declare module 'vue/types/vue' {
interface Vue {
clearGuards: (guard?: GuardName) => void;
beforeRouteLeave: BeforeRouteLeaveGuard;
afterRouteLeave: AfterRouteLeaveGuard;
}
}
export default function(Vue: VueConstructor) {
Vue.component('UiLink', Link);
Vue.mixin({
methods: {
/**
* Registers the guards if the current component has any.
*
* @param {Vue} component An instance of a component
*/
registerGuards(component: Vue) {
window.routerGuards = window.routerGuards || {};
component = component || this;
// Adds the last `beforeRouteLeave` encountered, for any component.
if (component && component.$options && Object.getPrototypeOf(component.$options).beforeRouteLeave) {
window.routerGuards.beforeRouteLeave = {
component: component,
call: Object.getPrototypeOf(component.$options).beforeRouteLeave,
};
}
// Adds the last `afterRouteLeave` encountered, for any component.
if (component && component.$options && Object.getPrototypeOf(component.$options).afterRouteLeave) {
window.routerGuards.afterRouteLeave = Object.getPrototypeOf(component.$options).afterRouteLeave;
}
},
/**
* Returns the result of the `beforeRouteLeave` guard. If `clear` is set to true, it will also
* clear the guard if the visit is not cancelled in order to avoid getting this guard again on the next clicks.
*
* @param {Vue} vm The Vue instance
* @param {Object} options The options passed to Inertia
* @param {MouseClick} event The event that triggered the guard
* @param {Boolean} clear Whether or not to clear the guards if it doesn't cancel the visit
*/
beforeRouteLeave(vm: Vue, options: any, event: MouseEvent, clear: boolean = true) {
let result = true;
if (window.routerGuards && window.routerGuards.beforeRouteLeave) {
result = window.routerGuards.beforeRouteLeave.call(
window.routerGuards.beforeRouteLeave.component || vm,
options,
event
);
}
if (clear && false !== result) {
this.clearGuards('beforeRouteLeave');
}
return result;
},
/**
* Calls the `afterRouteLeave` guard. If `clear` is set to true, it will also
* clear the all the guards, since this one is supposed to be the last one.
*
* @param {Vue} vm The Vue instance
* @param {Object} options The options passed to Inertia
* @param {Promise} visit The Inertia visit promise
* @param {MouseClick} event The event that triggered the guard
* @param {Boolean} clear Whether or not to clear the guards
*/
afterRouteLeave(vm: Vue, options: any, visit: Promise<any>, event: MouseEvent, clear: boolean = true) {
if (window.routerGuards && window.routerGuards.afterRouteLeave) {
window.routerGuards.afterRouteLeave.call(
window.routerGuards.afterRouteLeave.component || vm,
options,
event,
visit
);
}
if (clear) {
this.clearGuards();
}
},
/**
* Clears the guards.
*/
clearGuards(guard?: GuardName) {
if (!guard) {
window.routerGuards = {};
} else {
if (window.routerGuards && window.routerGuards[guard]) {
delete window.routerGuards[guard];
}
}
},
},
mounted() {
this.registerGuards(this);
},
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment