`this` undefined in vue-router beforeEach - vue.js

I'm trying to access the session in vue-router viathis.a.app, but it pops out 1 error.
After i debug, i found out that this is undefined.
this is the code im using to show this.
I had tried to use function(to, from, next) {...} instead of es6 syntax, but this is still undefined.
router.beforeEach((to, from, next) => {
if (!to.meta.isPublic){
// eslint-disable-next-line
console.log(this)
}
next()
})
Is there any configuration i need to make so that i can access this in vue-router?

Yes, you can use access "this" inside router beforeEach hook, but in a different way. The router has the root instance from where it is inserted
User router.app it is pointing to "this" (the root Vue instance)
router.beforeEach((to, from, next) => {
if (!to.meta.isPublic){
// eslint-disable-next-line
console.log(router.app)
}
next()
})

My best solution is to use Vue's nextTick
<script> // ignore this tag, it's just for hightlight
router.beforeEach((to, from, next) => {
// console.info('TO', to, 'FROM', from)
Vue.nextTick(() => {
if (newTerm !== oldTerm) {
router.app.getEasy(newTerm)
}
})
next()
})
</script>

Related

vue router route guard check vuex state

I have a route guard that looks like this. It checks the vuex store for a property, which is fetched async on page load. Since the code runs before the property is set, it always resolves as false.
Any ideas for a work around or a proper implementation?
router.beforeEach(async (to, from, next) => {
if (to.matched.some(record => record.meta.requiresActivated)) {
if (store.state.account.post_title !== 'true') {
next({
path: '/activate',
query: { redirect: to.fullPath, id: store.state.user.id }
})
}
next()
} else {
next()
}
})

Prevent route change within Vue compnent

Is it possible to prevent a route change within a Vue Component (not within my router file)?
My situation uses the same component, but the URL changes (/users/1 -> /users/2)
Vue.extend({
data: () => ({
active: true
}),
beforeRouteLeave(to, from, next){
if (this.active) {
// do not redirect
} else {
next();
}
}
})
My understanding is that this doesn't work when navigating the URL but the View/Component stays the same.
I need to use beforeRouteUpdate instead of beforeRouteLeave as stated in the docs
beforeRouteUpdate(to, from, next) {
if (this.active) {
next(false);
} else {
next();
}
},
If I'm using beforeRouteUpdate route url path in the browser not getting update, so I used beforeRouteLeave which is updating url and stop reloading same page.
beforeRouteLeave(to, from, next) {
if (this.active) {
next(false);
} else {
next();
}
}

trigger function after mounting any page in nuxt

Is it possible to write middleware in Nuxt to be triggered after mounting any page.
If I use the following middleware
export default function ({ app }) {
if (!process.server) {
app.$somePluginFunction()
}
}
it is triggered when navigating to that page, thus before mounting it. That is not what I am looking for.
I also know you can use the mounted() hook on an individual page, which is what I want, but I don't want to write the same mounted() hook to every page in my app manually. How can I do this?
There is many way to trigger a function before route change:
First use in default layout
// layout/default.vue
export default {
watch: {
$route () {
console.log('route changed', this.$route)
}
},
}
Second use before route:
https://router.vuejs.org/guide/advanced/navigation-guards.html#in-component-guards
router.beforeEach((to, from, next) => {
if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
else next()
})
Third write plugin like this:
how to write global router-function in nuxt.js
And write mixin like this :
Run function AFTER route fully rendered in Nuxt.js

Vue before each does not act on reload

BeforeEach won't act on page reload:
const router = new VueRouter({routes: Routes, mode: 'history'});
router.beforeEach((to, from, next) => {
Event.fire('loader-start', 'start');
next();
console.log(from);
console.log(to);
axios.post('/validate-route', {
from: from,
to: to,
}).then((res) => {
console.log(res);
next();
}).catch((err) => {
console.log(err);
next(false);
});
});
Vue.use(VueRouter);
I am trying to validate all routes on backend instead of adding beforeEnter on each router route.
But only that option work..
From here as answers say I've already added router to the top above using router.

Vuejs: Event on route change

On my main page I have dropdowns that show v-show=show by clicking on the link #click = "show=!show" and I want to set show=false when I change the route. Please advise me on how to realize this thing.
Setup a watcher on the $route in your component like this:
watch:{
$route (to, from){
this.show = false;
}
}
This observes for route changes and when changed ,sets show to false
If you are using v2.2.0 then there is one more option available to detect changes in $routes.
To react to params changes in the same component, you can watch the $route object:
const User = {
template: '...',
watch: {
'$route' (to, from) {
// react to route changes...
}
}
}
Or, use the beforeRouteUpdate guard introduced in 2.2:
const User = {
template: '...',
beforeRouteUpdate (to, from, next) {
// react to route changes...
// don't forget to call next()
}
}
Reference: https://router.vuejs.org/en/essentials/dynamic-matching.html
Just in case anyone is looking for how to do it in Typescript, here is the solution:
#Watch('$route', { immediate: true, deep: true })
onUrlChange(newVal: Route) {
// Some action
}
And yes as mentioned by #Coops below, please do not forget to include :
import { Watch } from 'vue-property-decorator';
Edit:
Alcalyn made a very good point of using Route type instead of using any:
import { Watch } from 'vue-property-decorator';
import { Route } from 'vue-router';
Watcher with the deep option didn't work for me.
Instead, I use updated() lifecycle hook which gets executed everytime the component's data changes.
Just use it like you do with mounted().
mounted() {
/* to be executed when mounted */
},
updated() {
console.log(this.$route)
}
For your reference, visit the documentation.
UPDATE
As stated by #CHANist, router.listen no longer works, I don't know from which version it stopped working, but the good news (as also stated by #CHANist) is we can use:
this.$router.history.listen((newLocation) => {console.log(newLocation);})
OLD Response
The above responses are the better, but just for completeness, when you are in a component you can access the history object inside the VueRouter with:
this.$router.history.
That means we can listen to changes with:
this.$router.listen((newLocation) => {console.log(newLocation);})
I think this is mainly useful when used along with this.$router.currentRoute.path
You can check what I am talking about placing a debugger
instruction in your code and begin playing with the Chrome DevTools Console.
import { useRouter } from "vue-router";
const router = useRouter();
router.afterEach((to, from) => { });
Using Vue3 and the composition API you can do
<script setup lang="ts">
import { watch } from "vue";
import { useRoute } from "vue-router";
const route = useRoute();
// do a `console.log(route)` to see route attributes (fullPath, hash, params, path...)
watch(
() => route.fullPath,
async () => {
console.log("route fullPath updated", route.fullPath);
}
);
</script>
References and examples here: https://router.vuejs.org/guide/advanced/composition-api.html#vue-router-and-the-composition-api
Another solution for typescript user:
import Vue from "vue";
import Component from "vue-class-component";
#Component({
beforeRouteLeave(to, from, next) {
// incase if you want to access `this`
// const self = this as any;
next();
}
})
export default class ComponentName extends Vue {}
using Vue Router is an alternative way, use the beforeRouteLeave after methods in your component like this:
<template>
<button #click="ShowMethod">DisplayButton</button>
</template>
<script>
data() {
return { show: true };
},
methods: {
ShowMethod() {
this.show = false;
}
},
beforeRouteLeave(to, from, next) {
this.show = false;
next();
}
</script>
according to VueJs documentation, it's called Navigation Guards check the link below:
Navigation Guards
The leave guard is usually used to prevent the user from accidentally
leaving the route with unsaved edits. The navigation can be canceled
by calling
In-Component Guards:
beforeRouteEnter
beforeRouteUpdate
beforeRouteLeave
beforeRouteLeave(to, from, next) {
// called when the route that renders this component is about to
// be navigated away from.
// has access to `this` component instance.
}
look at the below link for more information:
In-Component Guards
you can use the beforeEach event which allows any function to occur when the route is changing, just don't forget to call the next() function to proceed next operation, basically it has the same job as the backend expressJS middleWare.
router.beforeEach((to, from, next) => {
store.commit('setError', null); //in this example on each route I'm removing the error noted from the old route
document.title = `${to.meta.title} | HartWork`; //on each route I'm adding a prefix to document title.
next(); //calling next to proceed next functions and operations
})
I hope you doing well,
in vue3 and script setup this work is too easy:
watch(route, () => { fetch()})
be careful you must import before
import { watch } from 'vue';
import { useRoute } from 'vue-router';
and define use route :
const route = useRoute()