Building out a bootstrap-vue accordion and everything is working as expected however, i just added expand all / collapse all buttons which also function as I expected but now my issue is when I click on any of the accordion panels directly they ALL open. Is there a way to have them only open the clicked panel?
html:
<div class="container container-accordion-one">
<!--expand all / collapse all row -->
<div class="row row-expand-collapse">
<div class="offset-md-1 col-expand-collapse">
<ul class="list-expand-collapse">
<li><a href="#/" @click="showCollapse = true" class="font__card-body">Expand All</a></li>
<li><a href="#/" @click="showCollapse = false" class="font__card-body">Collapse All</a></li>
</ul>
</div>
</div>
<!--end: expand all / collapse all row -->
<div class="row">
<div class="offset-md-1 accordion-style-one">
<div role="tablist">
<b-card no-body class="">
<b-card-header href="#" v-b-toggle.accordion-1 header-tag="header" class="accordion-header" role="tab">
<p class="font__accordion-header">Accordion 1</p>
<i class="fal fa-plus accordionClosed" />
<i class="fal fa-minus accordionOpen" />
</b-card-header>
<b-collapse id="accordion-1" v-model="showCollapse" role="tabpanel">
<b-card-body>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Architecto distinctio enim fugit, inventore odio odit perferendis quas quo veritatis voluptate.</p>
</b-card-body>
</b-collapse>
</b-card>
<b-card no-body class="">
<b-card-header href="#" v-b-toggle.accordion-2 header-tag="header" class="accordion-header" role="tab">
<p class=" font__accordion-header">Accordion 2</p>
<i class="fal fa-plus accordionClosed" />
<i class="fal fa-minus accordionOpen" />
</b-card-header>
<b-collapse id="accordion-2" v-model="showCollapse" role="tabpanel">
<b-card-body>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Architecto distinctio enim fugit, inventore odio odit perferendis quas quo veritatis voluptate.</p>
</b-card-body>
</b-collapse>
</b-card>
<b-card no-body class="">
<b-card-header href="#" v-b-toggle.accordion-3 header-tag="header" class="accordion-header" role="tab">
<p class=" font__accordion-header">Accordion 3</p>
<i class="fal fa-plus accordionClosed" />
<i class="fal fa-minus accordionOpen" />
</b-card-header>
<b-collapse id="accordion-3" v-model="showCollapse" role="tabpanel">
<b-card-body>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Architecto distinctio enim fugit, inventore odio odit perferendis quas quo veritatis voluptate.</p>
</b-card-body>
</b-collapse>
</b-card>
</div>
</div>
</div>
</div>
js:
export default {
name: 'm',
components: {
LinksTo
},
data() {
return {
showCollapse: false
};
}
};
Since you want each collapse to be able to be individually opened or closed, you need to have a v-model
variable for each collapse. In the following I am using an array to store the collapse states:
<template>
<div>
<b-button @click="expandAll">Expand all</b-button>
<b-button @click="collapseAll">Collapse all</b-button>
<b-button block v-b-toggle.accordion-1 class="mt-2">Accordion 1</b-button>
<b-collapse id="accordion-1" v-model="collapseStates[0]">
<div>Lorem ipsum dolor sit amet.</div>
</b-collapse>
<b-button block v-b-toggle.accordion-2 class="mt-2">Accordion 2</b-button>
<b-collapse id="accordion-2" v-model="collapseStates[1]">
<div>Lorem ipsum dolor sit amet.</div>
</b-collapse>
<b-button block v-b-toggle.accordion-3 class="mt-2">Accordion 3</b-button>
<b-collapse id="accordion-3" v-model="collapseStates[2]">
<div>Lorem ipsum dolor sit amet.</div>
</b-collapse>
</div>
</template>
<script>
export default {
data() {
return {
collapseStates: [false, false, false]
}
},
methods: {
expandAll() {
this.collapseStates = this.collapseStates.map(x => true)
},
collapseAll() {
this.collapseStates = this.collapseStates.map(x => false)
}
}
}
</script>
See a working fiddle at: https://jsfiddle.net/p60zktLs/
You have to declare a separate showCollapse flags for each tab. And in shwo/collapse all turn on/off all of them.
EDIT:
Using DRY principals you are better breaking the accordion content out into data and only writing the markup once, then looping through your data. You can then track the open/close state on each accordion.
In your code, every accordion is modeled on the same variable, so they can only be all open or all closed. You need to have a separate state for each accordion.
Example: (simplified so it's easier to read, but you can do the same with bootstrap)
new Vue({ el: "#app", data: { allClosed: true, items: [{ title: 'title 1', description: 'description one', open: false }, { title: 'title 2', description: 'description two', open: false }, { title: 'title 3', description: 'description three', open: false } ], }, methods: { openCloseAll() { this.allClosed = !this.allClosed if (this.allClosed) this.items.map(x => x.open = false) else this.items.map(x => x.open = true) } } })
.accordian { margin: 8px 0; cursor: pointer; background: pink; padding: 0.25em; }
<div id="app"> <div> <button @click="openCloseAll()"> <template v-if="allClosed">Open</template> <template v-else>Close</template> All </button> </div> <div v-for="(item, i) in items" class="accordian" @click="item.open = !item.open"> <span>{{ item.title }}</span> <br /> <span v-if="item.open">{{ item.description }}</span> </div> </div> <script src="https://cdn.jsdelivr.net/npm/vue"></script>
Previous suggestion:
This is one way you could achieve such functionality:
new Vue({ el: "#app", data: { items: ['one', 'two', 'three', 'four', 'five'], openItems: [], openAll: true }, methods: { toggle(i) { const index = this.openItems.findIndex(x => x === i) if (index !== -1) this.openItems.splice(index, 1) else this.openItems.push(i) }, openCloseAll() { if (this.openAll) this.items.forEach((x, i) => this.openItems.push(i)) else this.openItems = [] this.openAll = !this.openAll } } })
.accordian { margin: 8px 0; cursor: pointer; background: pink; padding: 0.25em; }
<div id="app"> <div> <button @click="openCloseAll()"> <template v-if="openAll">Open</template> <template v-else>Close</template> All </button> </div> <div v-for="(item, i) in items" class="accordian" @click="toggle(i)"> {{ item }} <span v-if="openItems.includes(i)">opened</span> <span v-else>closed</span> </div> </div> <script src="https://cdn.jsdelivr.net/npm/vue"></script>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.