Updating URL Parameters in VueJS

To make it easier for users to share or bookmark the current state of an application. Let’s explore this feature with an example. In our example we will take a list that consists of names of people, cats and a dog. Each item in the list has a name and type. There is a filter for names and types. If you enter any text the items in the list that matches the name will be displayed. If more than one type is selected only the matching items will be shown. 

For example if you type a in the text box items that have the letter a in it will appear. If you select the filter that says only cats. The items that contain letter a and that belong to type cats will be displayed.

Sammy(cat)

Aleesa(cat)

Luna(cat)

<html>

<head>

</head>


<body>


<div id="app">

<h2>Items</h2>


<p>

<input type="search" placeholder="Filter by name" v-model="filter"> 

<input type="checkbox" value="person" id="personType" v-model="typeFilter"> 

<label for="personType">Only People</label>

<input type="checkbox" value="cat" id="catType" v-model="typeFilter"> 

<label for="catType">Only Cats</label>


<input type="checkbox" value="dog" id="dogType" v-model="typeFilter"> 

<label for="dogType">Only Dogs</label>

</p>


<ul>

<li v-for="item in items">{{ item.name }} ({{item.type }})</li>

</ul>

</div>


<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<script src="vue_url.js"></script>

</body>

</html>

Here is the JavaScript for the above code.

// hard coded for simplicity...

const ITEMS = [

{ name: "Ray", type: "person" },

{ name: "Lindy", type: "person" },

{ name: "Jacob", type: "person" },

{ name: "Lynn", type: "person" },

{ name: "Noah", type: "person" },

{ name: "Jane", type: "person" },

{ name: "Maisie", type: "person" },

{ name: "Carol", type: "person" },

{ name: "Ashton", type: "person" },

{ name: "Weston", type: "person" },

{ name: "Sammy", type: "cat" },

{ name: "Aleese", type: "cat" },

{ name: "Luna", type: "cat" },

{ name: "Pig", type: "cat" },

{ name: "Cayenne", type: "dog" }

]


const app = new Vue({

el:'#app',

data: {

allItems: ITEMS,

filter:'',

typeFilter:[]

},

computed: {

items() {

return this.allItems.filter(a => {

if(this.filter !== '' && a.name.toLowerCase().indexOf(this.filter.toLowerCase()) === -1) return false;

if(this.typeFilter.length && !this.typeFilter.includes(a.type)) return false;

return true;

});

}

}

});

The items referenced in HTML come from the ‘raw’ data, allItems. It is filtered in computed property. That is all about the application. Now we are going straight to our topic. 

Case 1:When you filter the data, change the URL without reloading the page.

Case 2: when requesting the page, check the URL for query params and default filters.

Here is the solution for the second one. 

created() {
	let qp = new URLSearchParams(window.location.search);
	let f = qp.get('filter');
	if(f) this.filter = qp.get('filter');
	let tf = qp.get('typeFilter');
	if(tf) this.typeFilter = tf.split(',');
},

The current URL query parameters can be seen by taking a look at the created event. If there is a value for filter you can pass it to this.filter.For typeFilter. Query string will be comma delimited. You can turn it into an array using the split function. Now the task is to update the URL when you use the filter. Vue watcher feature helps you associate a handler with a variable at a time. Using this feature you can handle updating the URL when you filter. We are using watcher for filter and typeFilter.

computed: {
	items() {
		this.updateURL();
		return this.allItems.filter(a => {
			if(this.filter !== '' && a.name.toLowerCase().indexOf(this.filter.toLowerCase()) === -1) return false;
			if(this.typeFilter.length && !this.typeFilter.includes(a.type)) return false;
			return true;
		});
	}
},

Here is the update URL.

updateURL() {
	let qp = new URLSearchParams();
	if(this.filter !== '') qp.set('filter', this.filter);
	if(this.typeFilter.length) qp.set('typeFilter', this.typeFilter);
	history.replaceState(null, null, "?"+qp.toString());
}