I am working on a project that includes 2 components where I have implemented a query-based search filter.
- PostsList component:
<template>
<div>
<PostFilter @change-filter="setFilters" />
<h3>Active filters</h3>
<pre>{{ activeFilters }}</pre>
<h3>Updated filters</h3>
<pre>{{ updatedFilters }}</pre>
</div>
</template>
<script>
import PostFilter from "../../components/posts/PostFilter.vue";
export default {
components: {
PostFilter,
},
data() {
return {
updatedFilters: {},
activeFilters: {
category: "",
query: "",
perPage: 5,
page: 1,
},
};
},
methods: {
setFilters(updatedFilters) {
console.log("Active filters");
console.log(this.activeFilters);
console.log("Updated filters");
console.log(updatedFilters);
this.$router.push({ query: updatedFilters });
if (this.$route.query.page) {
updatedFilters.page = 1;
}
this.activeFilters = updatedFilters;
},
objectEquals(obj1, obj2) {
for (var i in obj1) {
// eslint-disable-next-line
if (obj1.hasOwnProperty(i)) {
// eslint-disable-next-line
if (!obj2.hasOwnProperty(i)) return false;
if (obj1[i] !== obj2[i]) return false;
}
}
for (var j in obj2) {
// eslint-disable-next-line
if (obj2.hasOwnProperty(j)) {
// eslint-disable-next-line
if (!obj1.hasOwnProperty(j)) return false;
if (obj1[j] !== obj2[j]) return false;
}
}
return true;
},
},
};
</script>
- PostFilter component:
<template>
<div>
<select class="category" v-model="filters.category" name="category">
<option value="" selected>All categories</option>
<option
v-for="(category, index) in categories"
:key="index"
:value="category.id"
>
{{ category.title }}
</option>
</select>
<input
class="search"
v-model="filters.query"
type="search"
name="query"
placeholder="Search..."
/>
<select class="perPage" v-model="filters.perPage" name="perPage">
<option value="5">5 items / page</option>
<option value="10">10 items / page</option>
<option value="15">15 items / page</option>
<option value="20">20 items / page</option>
</select>
</div>
</template>
<script>
export default {
emits: ["change-filter"],
created() {
const query = this.$route.query;
if (
query &&
Object.keys(query).length > 0 &&
query.constructor === Object &&
this.hasFilterKeys(query)
) {
this.filters = { ...this.filters, ...this.$route.query };
}
this.fetchCategories();
},
data() {
return {
filters: {
category: "",
query: "",
perPage: 5,
},
awaitingSearch: false,
categories: [],
};
},
watch: {
"filters.category": function (currentValue, oldValue) {
if (oldValue !== currentValue) {
this.emitFilters();
}
},
"filters.query": function (currentValue, oldValue) {
// eslint-disable-next-line
if (oldValue != currentValue) {
if (!this.awaitingSearch) {
setTimeout(() => {
this.emitFilters();
this.awaitingSearch = false;
}, 1000);
}
this.awaitingSearch = true;
}
},
"filters.perPage": function (currentValue, oldValue) {
if (oldValue !== currentValue) {
this.emitFilters();
}
},
},
methods: {
emitFilters() {
let cleanFilters = this.cleanObject(this.filters);
this.$emit("change-filter", cleanFilters);
},
cleanObject(obj) {
for (var propName in obj) {
if (
obj[propName] === null ||
obj[propName] === undefined ||
obj[propName] === ""
) {
delete obj[propName];
}
}
return obj;
},
async fetchCategories() {
this.categories = [
{
id: 1,
title: "Anatomy",
},
{
id: 2,
title: "Biology",
},
{
id: 3,
title: "Algebra",
},
{
id: 4,
title: "Chemistry",
},
{
id: 5,
title: "Computer Science",
},
{
id: 6,
title: "English",
},
];
},
hasFilterKeys(obj) {
for (const key in this.filters) {
// eslint-disable-next-line
if (obj.hasOwnProperty(key) && obj[key] != "") {
return true;
}
}
return false;
},
},
};
</script>
Every time the filters are changed or updated, an API request needs to be sent. However, I am encountering the issue of receiving same values in both the activeFilters
and the incoming filters from the setFilters()
method of the PostsList component. Why is the old value of activeFilters
being lost before setting new values in my case?
For a real working example with code snippets, you can visit here.
You can also view an example video below:
<blockquote class="imgur-embed-pub" lang="en" data-id="a/Y4gauRM" ><a href="//imgur.com/a/Y4gauRM">Same object values on search</a></blockquote><script async src="//s.imgur.com/min/embed.js" charset="utf-8"></script>