Nick Maddren
Nick Maddren

Reputation: 661

State history with browser back button vue.js

I am developing an application with Vue and Laravel. Laravel is controlling my routes and I'm not using the vue-router.

I am conditionally loading some components based on the state of an object in my parent components data.

I have this method in my parent component:

  activateListingForm: function() {
    this.listingFormActive = !this.listingFormActive;
  }

This method is triggered by a button that will change this.listingFormActive to true or false.

I then have this in the template of the component:

  <transition name="slide-fade">
    <create-listing-form v-if="listingFormActive"></create-listing-form>
    <listings-table v-else></listings-table>
  </transition>

A problem that I am having is that some users are clicking the browser back button expecting the last component to load. I'm wondering if there is a way to change the state based on the back button?

Thanks

Upvotes: 3

Views: 15054

Answers (1)

Jacob Goh
Jacob Goh

Reputation: 20855

It's doable. My colleagues and I had to do something similar while working on this page.

For it to work,

  • url is the source of truth of what the value of listingFormActive should be
  • the state of listingFormActive should be stored in url everytime it changes.
  • the initial state of listingFormActive should be retrieved from url

First, watch listingFormActive. Everytime the state change, perform pushState to store its state as a url query.

watch: {
    listingFormActive: {
        handler(v) {
            history.pushState({
                listingFormActive: v
            }, null, `${window.location.pathname}?listingFormActive=${v}`);
        }
    }
}

Add some utility method for getting url query

methods: {
    currentUrlQuery() {
        return window.location.search
            .replace("?", "")
            .split("&")
            .filter(v => v)
            .map(s => {
                s = s.replace("+", "%20");
                s = s.split("=").map(s => decodeURIComponent(s));
                return {
                    name: s[0],
                    value: s[1]
                };
            });
    },
    getListingFormActive() {
        return this.currentUrlQuery().filter(obj => obj.name === 'listingFormActive').value;
    }
}

the initial state of listingFormActive should be based on what you saved in the url

data() {
    return {
        listingFormActive: this.getListingFormActive() == 'true' ? true : false
    }
},

Upvotes: 5

Related Questions