Reputation: 95
I have an array of objects like this (continents):
data() {
return {
continents: [
{
name: "South America",
countries: [
{
name: "Paraguay"
},
{
name: "Chile"
}
]
},
{
name: "North America",
countries: [
{
name: "Costa Rica"
},
{
name: "Mexico"
}
]
}
]
}
}
// 6 continents and over 250 countries within.
And Im trying to filter it with v-model
'filter' like this
computed: {
filtered() {
return this.continents.filter(continent => {
continent.countries = continent.countries.filter(country => {
return country.name.match(new RegExp(this.filter, 'i'));
});
return continent.countries.length;
});
}
}
And render it with v-for
directive like this:
<input v-model="filter" type="text">
<div v-for="continent in filtered" v-if="filtered.length" class="countries-group">
<h4>{{ continent.name }}</h4>
<ul class="country-list">
<li v-for="country in continent.countries" class="country-item">{{ country.name }}</li>
</ul>
</div>
And it almost works, but my computed property filtered modifies the original countries data, so when i'm trying to backspace filter v-model
, it not return the inited data because its already overriding with filtered objects.
Upvotes: 1
Views: 2077
Reputation: 34286
my computed property filtered modifies the original contries data
You shouldn't do this. Don't modify state within computed properties because it may trigger other computed properties to be re-evaluated and cause confusing bugs. Computed properties are meant to be pure functions which transforms (without mutating) the component's state in some way.
Try this:
filtered() {
const filter = this.filter.toLowerCase();
return this.continents
.map(continent => Object.assign({}, continent, {
countries: continent.countries.filter(country => {
return country.name.toLowerCase().includes(filter);
}),
})
.filter(continent => continent.countries.length);
}
Upvotes: 2