Reputation: 81
I am currently making an accordion from data coming from a service (I have made an object named "groups" for example). Currently, I can click on the Group Name and it will hide/show the Description correctly, however it opens all instances. How can I make it open the group that was clicked, instead of all?
Here is my fiddle: https://jsfiddle.net/ch609uov/1/
I know I can use the open property in my groups var, however the actual data I am working with does not have that property. So, I need it to work with the isExpanded prop which I have added to my Vue instance.
var groups = {
"GROUP A": {
"name": "GROUP A",
"open": false,
"desc": "description 1",
"heading": "test",
"items": [
"item 1"
]
},
new Vue({
el: ".vue",
data: {
groups: groups,
heading: "Plan Communications",
isExpanded: false
}
})
Upvotes: 2
Views: 19059
Reputation: 7165
There are a few ways you can go about doing this, the first way actually modifies the data returned from the external resource in such a way that each entry has its own open
attribute:
let serviceDataExample = [{title: "some title 1"}, {title: "some title 2"}, {title: "some title 3"}];
serviceDataExample.forEach(obj => {
obj.open = false;
});
console.log(serviceDataExample);
// assign to your data object with `this` and use the open
// attribute individually in the template
In the above, serviceDataExample
is just a mock representation of what the data might look like.
The downside to the solution above is that every time you fetch new data from the resource, you're going to have to essentially re-run the forEach
before assigning it to your data object.
Doing it this way ensures that you never have to clutter the original (local) resource data with display settings:
var groups = {
"GROUP A": {
"name": "GROUP A",
"open": false,
"desc": "description 1",
"heading": "test",
"items": [
"item 1"
]
},
"GROUP B": {
"name": "GROUP B",
"open": false,
"desc": "description 2",
"items": [
"item 1",
"item 2",
"item 3",
"item 4",
"item 5",
"item 6",
"item 7"
]
},
"GROUP C": {
"name": "GROUP C",
"open": false,
"desc": "description 3",
"items": [
"item 1",
"item 2",
"item 3",
"item 4",
"item 5"
]
},
"GROUP D": {
"name": "GROUP D",
"open": false,
"desc": "description 4",
"items": [
"item 1",
"item 2",
"item 3",
"item 4",
"item 5",
"item 6",
"item 7"
]
},
"GROUP E": {
"name": "GROUP E",
"open": false,
"desc": "description 5",
"items": [
"item 1",
"item 2",
"item 3",
"item 4",
"item 5"
]
}
}
new Vue({
el: ".vue",
data: {
groups: groups,
heading: "Plan Communications",
// isExpanded: false,
expandedGroup: []
},
methods: {
isExpanded(key) {
return this.expandedGroup.indexOf(key) !== -1;
},
toggleExpansion(key) {
if (this.isExpanded(key))
this.expandedGroup.splice(this.expandedGroup.indexOf(key), 1);
else
this.expandedGroup.push(key);
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div class="container vue">
<div v-for="(group, key) in groups">
<a @click="toggleExpansion(key)" >{{group.name}}</a>
<ul v-show="isExpanded(key)">
<li>{{group.desc}}</li>
</ul>
<hr>
</div>
</div>
Here, we are creating an external data attribute in order to keep track of the index of the group that is expanded. If the group
's index exists within the local expandedGroup
, then it is open, if not, it is closed.
Hope this helps!
Upvotes: 3