Toggle class when routing to a specific page

vue-router

#1

I have a page with a lot of content that takes a bit to load, so I would like to display a loader everytime somebody goes to that route.

To do this, I wanted to toggle a class in a component with beforeRouteEnter, so that the component would be triggered when navigating to nameofthepage. The component is in the layout and looks like this:

<template>
    `<div class="loading-page" :class="{'enter--shop':enterShop}"></div>`
</template>
<script>
export default {
  beforeRouteEnter (to, from, next) {
    if (to.name.startsWith('nameofthepage')) {
      next(vm => 
          vm.enterShop = true
      })
    } else next()
  },
  data: function() {
      return {
        enterShop: false
    }
  }
}
</script>

But now when I navigate to nameofthepage, class is not triggering. Any help would be appreciated. Thanks!


#2

That won’t work because until you have entered the route nothing will be displayed.

You could do something like this within your component.

<template>
	<div class="spinner" v-show="isLoading"/>
</template>


data() {
	return {
		isLoading: true
	}
}

mounted() {
	this.fetchData().then(function() {
  		this.isLoading = false
	})
}

#3

The point is that I want to display a loader in the interval between I click the link to that page and it gets to the mounted hook. Right now, I have 1-2 seconds where no component is displayed (just the layout).

For that, I would need a way to display an element when the route change is fired, and then remove it when it gets to mounted.


#4

In order to display a spinner using beforeRouteEnter you would need to have a spinner component placed on the root level of your app and use vuex to listen to the state which is mutated by your beforeRouteEnter method.


#5

Finally I did it with an animation

<template>
  <div class="loading-page" :class="{'enter--shop':$route.name.startsWith('nameofthepage')}">
</template>

<style>

.enter--shop {
   opacity: 1;
   visibility: visible;
   animation: kill-loader 2s forwards ease;
}

@keyframes kill-loader {
 
 0% {
    opacity:1;
  }
 
 100% {
    opacity:0;
    visibility: hidden;
    display: none;
  }
}
</style>

The duration is fixed, which can be bad for some cases, but for this particular case having a fixed duration spinners feels nice and less ‘jumpy’.


#6

Based on your explanation of your problem it sounds like you are not doing something correctly. If you provide a working example surely we can point out what need to be fixed as it sounds like your trying to use a hack instead of fixing the underlying problem.


#7

Provide a working fiddle if you want further help because you are definitely going in the wrong direction.

I suggest that you work off the first example I provided and you will start to understand how to achieve a spinner that works how you intend it to.


#8

The point is that my main page takes a while to parse the html. So there is a gap between when the route changes and when mounted() is fired. So in that gap, I can just see the layout.


#9

What you need to do is simple.

1.) Enter the route and display only the spinner
2.) Fetch your data in the mounted hook and remove the spinner on success and display the content.

The spinner will appear immediately and nothing else will be displayed until it’s ready.

You must have some additional logic that is not correctly implemented and unless you provide a working example there is little else that can be done to help you.


#10

No worries, thanks for your help.

The point is that data is already fetched (at nuxtServerInit), so it is the rendering that takes a while). And with the mounted hook, even if I just display the spinner, there is a short lapse where there is no content and no spinner.

This short lapse is avoided using setting the class with $route.name.startsWith, so actually setting the animation to 1s is a good solution for me (as in my experience, a spinner that lasts less than that seems too ‘jumpy’)


#11

then you are doing something incorrectly


#12

I agree. This is surely the wrong approach. If you’re happy with it then fine but if you want to improve your code, you will need to provide an example or more information. If it’s a rendering problem maybe you should paginate your data or optimise your content etc


#13

If you already have the data, but rendering is taking seconds then something isn’t right with your implementation. When done correctly, rendering should take milliseconds.


#14

Ok, I see. How could I debug that? (I’m using Nuxt)


#15

Impossible to say without seeing what’s going on. We’d need to see the related code to see if anything stands out.

You can also look to Chrome DevTools’ Performance analyser to help find bottlenecks. https://developers.google.com/web/tools/chrome-devtools/evaluate-performance/