Reputation: 2485
Im struggling to implement something which I think is pretty easy.
In my Vue app I loop through a list. Each list item is a child component. Each list item has an expand/collapse button. That works fine, but I want to be able to close all open items from the parent and I don't seem to be able to get that working as I would like.
The expand/collapse is controlled via a variable called isOpen
so
<div v-if="isOpen">Something here</div>
I have tried using a computed property instead of the isOpen and passing props but that issue is I think it needs to act more like an event.
Consider three open list items. If the list items are controlled by a prop, and setting it to false
closes the items, when an item is reopened, the prop is still false
so therefore will not work a second time. I know I could change it back on the parent, but it seems wrong.
Whats the best way to accomplish this?
Upvotes: 1
Views: 999
Reputation: 43881
If you passed an "allClosed" prop, you would need to have your child components emit events to reset it every time they opened. That seems hacky to me. I think you are right that it should be more of a parent-to-children event, which calls for an event bus.
new Vue({
el: '#app',
data: {
closeBus: new Vue(),
kids: [1, 2, 3]
},
components: {
expandableThing: {
data() {
return {
isOpen: true
}
},
props: ['bus'],
methods: {
toggle() {
this.isOpen = !this.isOpen;
}
},
created() {
this.bus.$on('close', () => this.isOpen = false);
}
}
}
});
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.min.js"></script>
<div id="app">
<expandable-thing v-for="kid in kids" inline-template :bus="closeBus">
<div>
<div v-show="isOpen">My stuff!</div>
<button @click="toggle">Toggle</button>
</div>
</expandable-thing>
<button @click="closeBus.$emit('close')">Close all</button>
</div>
Upvotes: 1