1

I'm building a "Nav/Progress Bar" component which shows users how far along in the application flow they are, using Nuxt.js with Bootstrap-Vue. The progress bar works fine when the user follows a <nuxt-link> to the next page. However, if the user reloads the page, the progress bar will reset to its default state.

As you can see in the example below, I'm using a Vue watcher to update the progress bar on an update to the page route. However, this watcher does not work when a page is reloaded (I assume this is because, on reloading a page, the page route does not change). But how else could I force the progress bar to load the current status?

I have a feeling the solution should be pretty simple, but I'm at a loss. I'm new to Vue, so please excuse me if I've missed anything obvious. Thanks!

Image of progress bar on Page One - "Page One Appearance"

Image of progress bar on Page Two - "Page Two Appearance"

Here is my HTML <template>:

<template>
  <div>

    <div class="row">
      <div>
        <b-link to="/" v-bind:class="{ 'font-weight-bold text-primary':   pageOneActive, 'text-secondary font-weight-normal':   pageOneInactive }" >
          Build
        </b-link>
      </div>
      <div>
        <b-link v-bind:to="reviewLink" v-bind:class="{ 'font-weight-bold text-primary': pageTwoActive, 'text-secondary font-weight-normal': pageTwoInactive }" >
          Review
        </b-link>
      </div>
    </div>

    <b-progress :max="2">
      <b-progress-bar :value="progressIndicator"></b-progress-bar>
    </b-progress>

  </div>
</template>

And my <script looks like this:

<script>
import Bootstrap from "bootstrap-vue";
export default {
  data() {
    return {
      pageName: this.$nuxt.$route.name,
      progressIndicator: 1,
      progressSuccess: 0,
      pageOneActive: true,
      pageOneInactive: false,
      pageTwoActive: false,
      pageTwoInactive: true,
    };
  },
  watch: {
    "$route.path": function() {
      let pageName = "index";
      let progressIndicator = 1;
      let progressSuccess = 0;
      let pageOneActive = null;
      let pageOneInactive = null;
      let pageTwoActive = null;
      let pageTwoInactive = null;

      function setPageInactive() {
        pageOneActive = false;
        pageOneInactive = true;
        pageTwoActive = false;
        pageTwoInactive = true;
      }

      pageName = this.$nuxt.$route.name;
      console.log(pageName);

      if (pageName === "index") {
        setPageInactive();
        progressIndicator = 1;
        pageOneActive = true;
        pageOneInactive = false;
      } else if (pageName === "review") {
        setPageInactive();
        progressIndicator = 2;
        pageTwoActive = true;
        pageTwoInactive = false;
      }

      console.log(progressIndicator);
      
      this.progressIndicator = progressIndicator;
      this.progressSuccess = progressSuccess;
      this.pageOneActive = pageOneActive;
      this.pageOneInactive = pageOneInactive;
      this.pageTwoActive = pageTwoActive;
      this.pageTwoInactive = pageTwoInactive;
    }
  }
};
</script>

(I know this is not the most efficient way to do things, with Inactive + Active variables, vs basing the css changes on one variable change. I just haven't had the time to change it yet.)

1 Answer 1

1

The reason the progress bar resets to its default state, when the user reloads the page, is because in the data property, the progress indicator is 1. Reloading the page "resets" the data properties to their default values.

However, you can capture the values on reload using the created/mounted lifecycle hook. Here, I decided to use the mounted hook. You make the same checks you made in the watcher. In order to avoid duplication, I extracted it into a function and removed redundant code. You can restore them to their original condition, if you please. The idea is the same.

Let your script section be something like this:

<script>
import Bootstrap from "bootstrap-vue";
export default {
  data() {
    return {
      pageName: '',
      progressIndicator: 0,
      pageOneActive: true,
      pageTwoActive: false,
    };
  },
  methods: {
    determinePageProgressIndicator() {
      this.pageName = this.$nuxt.$route.name;
      this.progressIndicator = this.pageName === "index" ? 1 : 2  // this is ok now as there are only two page names. If there are more, the logic will be more complex.
      this.pageOneActive = this.pageName === 'index';
      this.pageTwoActive = this.pageName === 'review';
    }
  },
  mounted() {
    this.determinePageProgressIndicator();
  },
  watch: {
    "$route.path": function() {
      this.determinePageProgressIndicator();
    }
  }
};
</script>

You don't need pageOneInactive and pageTwoInactive as in JavaScript, you can determine these using the logical NOT (!) operator.

If you know pageOneActive = true, then you can replace pageOneInactive with !pageOneActive. The logical NOT operator will evaluate the expression to false.

You can read more about the logical NOT operator here;

In your template, you then do

<template>
  <div>

    <div class="row">
      <div>
        <b-link to="/" v-bind:class="{ 'font-weight-bold text-primary':   pageOneActive, 'text-secondary font-weight-normal':   !pageOneActive }" > // replace pageOneInactive
          Build
        </b-link>
      </div>
      <div>
        <b-link v-bind:to="reviewLink" v-bind:class="{ 'font-weight-bold text-primary': pageTwoActive, 'text-secondary font-weight-normal': !pageTwoActive }" > // replace pageTwoInactive
          Review
        </b-link>
      </div>
    </div>

    <b-progress :max="2">
      <b-progress-bar :value="progressIndicator"></b-progress-bar>
    </b-progress>

  </div>
</template>

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you Tony. A lot of things “clicked” for me after reading your answer. Much appreciated!
I am happy to help. :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.