I have a search form and a results page build with Nuxt JS. I am attempting to redirect the results page pages/results/index.vue
back to the search page pages/search/index.vue
if the form returns errors.
I am attempting to use In-Component Guards per the Vue documentation
According to the docs:
However, you can access the instance by passing a callback to next. The callback will be called when the navigation is confirmed, and the component instance will be passed to the callback as the argument:
beforeRouteEnter (to, from, next) { next(vm => { // access to component instance via `vm` }) }
// version info
├─┬ [email protected]
│ ├─┬ @nuxt/[email protected]
│ │ └─┬ @nuxt/[email protected]
│ │ └── [email protected] deduped
│ └─┬ @nuxt/[email protected]
│ └─┬ @nuxt/[email protected]
│ └── [email protected] deduped
└─┬ [email protected]
└── [email protected]
My main issue is that the callback in the next()
function in the navigation guard does not seem to work to re-route the page.
(the from page)
// page/search/index.vue
<template>
...
<nuxt-link to="/results" @click.native="doSearch">
Show Results
</nuxt-link>
...
</template>
<script>
export default {
...
methods: {
doSearch () {
... // validates search fields and adds content to store
}
},
...
}
</script>
The above works fine, where doSearch
validates the form and adds the results (along with any errors) to the store.
But then in the following...
(the to page)
// pages/results/index.vue
<script>
export default {
...
beforeRouteEnter (to, from, next) {
next((vm) => {
console.log(vm.validateRoute()) // works: '/search'
vm.validateRoute() // does not work: does nothing
})
},
...
computed: {
errors () {
return this.$store.state.errors
}
},
...
async fetch ({ store, params }) {
await store.dispatch('searchresults/GET_RESULTS')
},
...
methods: {
validateRoute () {
let route = true
if (this.errors.length > 0) {
route = '/search'
}
console.log(this.erros.length) // works: 7
console.log(route) // works: '/search'
return route
}
},
...
}
</script>
The callback in beforeRouteEnter
does not appear to be evaluated and does not cause the route to change. Note the logging shows the callback is firing and returning the proper value(s).
If I explicitly define the route, without using a callback function, it works:
// pages/results/index.vue
<script>
export default {
...
beforeRouteEnter (to, from, next) {
next('/search') // works: re-routes to '/search' every time
},
...
}
</script>
I tried several iterations of the next(callback)
with limited success...
next(() => { return false }) // does not work
next(function () { return false }) // does not work
But only explicit declarations work...
next({ path: false }) // works: prevents route change
next({ path: '/search' }) // works: changes route to '/search'
I'm at a total loss; is this a bug, or am I missing something?
Addendum
I previously tried using middleware as mentioned in the Nuxt documentation here. However this resulted in an endless loop, as discussed in this blog post.
// middleware/validate.js
export default function ({ store, redirect }) {
console.log('middleware: validate') // 'middleware: validate'
if (store.state.errors.length > 0) {
return redirect('/search') // ...endless loop
}
return true // otherwise this works
}
// nuxt.config.js
export default {
...
router: {
middleware: "validate"
},
...
}
Fixed
As pointed out by @ifaruki, placing the middleware call inside the page component fixes the endless loop issue:
Next step is to add your middleware to your page pages/results/index.vue like this:
export default { middleware: 'validate' }
I found this at the very end of the docs which appears to be the Nuxt method for Vue JS In-component Guards:
You can add your middleware to a specific layout or page as well:
pages/index.vue
orlayouts/default.vue
:facepalm:
For this case nuxt.js has a property called middleware
.
You could use the middleware
instead of the guards. In your middleware folder you create first a file called for example validate.js
.
In your validate.js
file you create an function and put your validate logic in there:
export default function ({ store, redirect }) {
if (store.state.errors.length > 0) {
return redirect('/search')
}
}
Now you have set up your middleware. Next step is to add your middleware to your page pages/results/index.vue
like this:
export default {
middleware: 'validate'
}
The middleware is always called before the vue instance is created. Whenever store.state.errors
is bigger 0, you will get redirected back to /search
otherwise this middleware just gets ignored.
Always read the nuxt docs first because nuxt does not always have the same behaviour like vue.js or vue.js router Official docs: https://nuxtjs.org/api/pages-middleware
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With