Reputation: 1763
The issue is that I'm selecting options, storing them in an object and using v-for to iterate over the keys of the object and display the selected options. Here's my code:
data() {
return {
points: 100 as number,
categories: [{name: "Fitness", items: "6"}, {name: "Electronics", items: "10"},
{name: "Fitness", items: "6"}, {name: "Electronics", items: "10"},
{name: "Fitness", items: "6"}, {name: "Electronics", items: "10"}] as Array<Record<string, string>>,
filters: {} as Record<string, number>
};
}
and the html
<div id="filterContainer" class="d-flex flex-column">
<div class="d-flex flex-row justify-content-between">
<p id="recent">All Categories</p>
<div class="ellipsesDropdown">
<div class="d-flex flex-column">
<FilterIcon id="filterIcon" />
<div v-if="filterKeys() > 0" class="filterDot align-self-end"></div>
</div>
<div class="dropdown-content">
<p v-for="(cat, ind) in categories" :key="ind" @click="filters[cat.name] = 1">{{cat.name}} ({{cat.items}})</p>
</div>
</div>
</div>
<div class="d-flex flex-row flex-wrap" style="height: 32px;">
<div v-for="(val, key, ind) in filters" :key="ind" class="filterSelection d-flex flex-row">
{{key}}
<CloseIcon @click="delete filters[key]" class="closeIcon" />
</div>
<p v-if="filterKeys() > 0" @click="filters = {}" class="clearAllText">Clear all</p>
</div>
</div>
There aren't any errors in the console. I've logged the filters data object on click and values do get added to it. What am I missing?
EDIT: Here's a link to a fiddle that I created: https://jsfiddle.net/ayudh37/2uqm9nar/3/
EDIT 2: Read about the issue I encountered here: https://v2.vuejs.org/v2/guide/reactivity.html
Upvotes: 0
Views: 420
Reputation: 88
I think the more elegant solution would be if you (if you can) set your data in the data object:
...
data: {
filters: {
"apples": null,
"oranges": null,
"pears": null
},
categories: ["apples", "oranges", "pears"]
},
...
This way, you tell vue to watch all this data. This might not always be possible (e.g. in that example case you given) but often, this is enough.
It's a combination of how javascript works and how VueJS handles it.
E.g. if you have a variable:
let foo = null
deep in machine code, foo points to a memory address, but since it is null, it doesn't show yet. if you set it the first time:
foo = 'bar'
foo shows to that memory address and vue-view, e.g. {{foo}} updates it.
If you now change it:
foo = 'test'
foo will point to 'test' if you console.log() it, but VueJS still shows 'bar'. With $set you force that behaviour, but you'd do so also by setting it within data.
It's a simple explanation and not 100% true and gets more complicated with object and arrays (because these are list of pointers), but it'll help you a lot in future if you read through all these stuff.
Upvotes: 1
Reputation: 6978
Use $set
and it works. It's just reactivity issue.
this.$set(this.filters,cat,1);
fiddle - https://jsfiddle.net/Lejxtbm0/6/
Upvotes: 2