I would like to reliably know which layout and page is currently being rendered outside the page component itself. I would like to make adjustments to various layout components, such as styling the body tag and tweaking the state of a header component and so on.
Right now I'm using a _mixin_ called currentPage with rudimentary detection that looks like this:
currentPage () {
if (this.$nuxt && this.$nuxt.$route) {
// Home page
if (!this.$nuxt.$route.path || this.$nuxt.$route.path === '/') {
return 'home'
// Current page (or current route)
} else if (this.$nuxt.$route.name) {
return this.$nuxt.$route.name
}
}
// Assume the user is on error page
return 'error'
}
This works in most cases, however it breaks when I'm triggering the error using error() in asyncData. In my example, I'm triggering an error from asyncData if I can't find a resource from my CMS, but my currentPage computed thinks the user is on the original page.
Something like this:
asyncData ({ error }) {
return Promises.all([ /* fetch data from Contentful*/ ]).then((contentfulData) => {
if (!contentfulData.items.length) {
error({
statusCode: 404,
message: 'Not found'
})
}
})
}
In this case, the user will see an error page, but I can't find any way of actually detecting that this is happening outside of my error.vue code. The router still thinks the user is on the original page (which is half true, since the URL did not change). I would imagine there are other scenarios where the current route does not match the rendered page as well.
I can think of a few hacky workarounds to some of the things I'm trying to use this for, but it feels a little bit weird that the name of the page component that is being rendered is not available anywhere. I also tried getting the error data from under this.$nuxt.nuxt.err, but this does not seem to be reactive.
@Eiskis before diving into this any further, have you tried the following?
$nuxt.$on('routeChanged', (to, from) => {
})
Not a very fancy way to do it, but let me know if it solves it for you. From what I could gather, this event is fired even when there's an error. I'll reopen the issue if I'm mistaken.
Thanks @galvez. You were right, it's not pretty but it works. Ran into another issue when setting body classes based on the error state upon mounting hook, so I had to add a setTimeout to make this work when landing on a page with error.
Here's what I ended up with: https://gist.github.com/Eiskis/896d4878d8bb75d60f9a8b66cc760f9c
export default {
head () {
const page = (this.hasNuxtError ? 'error' : this.currentPage)
return {
bodyAttrs: {
class: [
'body-' + this.$options.name,
'body-page-' + page
].join(' ')
}
}
},
data () {
return {
hasNuxtError: false
}
},
mounted () {
this.$nuxt.$on('routeChanged', this.onRouteChange)
setTimeout(this.onRouteChange, 1)
},
beforeDestroy () {
this.$nuxt.$off('routeChanged', this.onRouteChange)
},
methods: {
onRouteChange () {
// This is not reactive, so we must manually look into it on route change
if (this.$nuxt.nuxt.err && !this.hasNuxtError) {
this.hasNuxtError = true
} else if (!this.$nuxt.nuxt.err && this.hasNuxtError) {
this.hasNuxtError = false
}
}
}
}
Would be awesome if the error data was reactive, but it's not a big deal to write this once in a mixin or something.
You can replace setTimeout(this.onRouteChange, 1) with this.$nextTick(() => this.onRouteChange) though.
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Most helpful comment
Thanks @galvez. You were right, it's not pretty but it works. Ran into another issue when setting body classes based on the error state upon mounting hook, so I had to add a
setTimeoutto make this work when landing on a page with error.Here's what I ended up with: https://gist.github.com/Eiskis/896d4878d8bb75d60f9a8b66cc760f9c
Would be awesome if the error data was reactive, but it's not a big deal to write this once in a mixin or something.