Reputation: 1109
I'm working with BootstrapVue
.
I have following situation: I have a parent.vue
and a child.vue
. In my parent.vue
I have a v-for
where I can create multiple Buttons
. Each of these is triggering a b-collapse
in my child.vue
and each of this has multiple b-collapse
as well. (see Code)
Now I need to do following: I want to close all of my b-collapse
inside my child.vue
when my b-collapse
in my parent.vue
will be closed. But I could not figure out how to do that.. (they should be closed as well when I reopen my parent.vue
-collapse)
I have reduced my code to the minimum. But just for additional info I will do this.inputs.push[{id: this.id +=1}]
each time adding a new Item or Element. So each of them has an unique id
.
Hopefully someone can help me out!
CODE
parent.vue
<div v-for="item in inputs" :key="item.id">
<b-button v-b-toggle="'NewItem'+item.id"></b-button>
</div>
<Child/>
<b-button @click="addNewItem()"></b-button>
child.vue
<b-collapse visible :id="'NewItem' + item.id"> //Here i need a solution
<div v-for="element in inputs" :key="element.id">
<b-button v-b-toggle="'Element' + element.id"></b-button>
<b-collapse :id="'Element' + element.id>
<div>Here is Element {{element.id}}</div>
</b-collapse>
</div>
<b-button @click="addElement()"></b-button>
</b-collapse>
EDIT - Full Code:
Parent.vue
<template>
<div class="container">
<div v-for="(item, index) in inputs" :key="item.id">
<b-button v-b-toggle="'NewItem'+item.id" @click="closeAll()">Item {{index + 1}}</b-button>
</div>
<Child :idParent="item.id" :closeAllProducts="closeAllProducts" />
<b-button @click="addNewItem()">Add new Item</b-button>
</div>
</template>
<script>
import Child from "./components/child.vue"
export default {
components: {
Child,
},
data() {
return {
closeAllProducts: true,
id: 1,
inputs: [{
id: 1,
}]
}
},
methods: {
addNewItem() {
this.inputs.push({id: this.id += 1})
},
closeAll() {
this.closeAllProducts = false;
}
}
}
</script>
Child.vue
<template>
<b-collapse :visible="closeAllProducts" :id="'NewItem'+item.id">
<div v-for="(element, index) in inputs" :key="element.id">
<b-button v-b-toggle="'Element' + element.id"></b-button>
<b-collapse :id="'Element' + element.id">
<div>Here is Element {{index + 1}}</div>
</b-collapse>
</div>
<b-button @click="addElement()">Add new Element</b-button>
</b-collapse>
</template>
<script>
export default {
props: ["idParent", "closeAllProducts"],
data() {
return {
id: 1,
inputs: [{
id: 1,
}]
}
},
methods: {
addElement() {
this.inputs.push({id: this.id += 1})
}
}
}
</script>
NEW EDIT: Added closeAllProducts
- If I'm clicking my button
in my parent.vue
it should trigger the function to change the boolean
to **false**
. But when I use it like this all elements in every item will be non visible
.. I need to pass a parameter
with it but I could not figure out how..
Upvotes: 6
Views: 904
Reputation: 138526
One solution is to create a child prop that collapses its b-collapse
elements, and have the parent control that prop:
Create a Boolean prop named collapsed
in the child:
// child.vue
export default {
props: {
collapsed: Boolean
}
}
In addElement()
, insert a visible
prop to match the b-collapse
's visible
prop. We'll bind each item's visible
to the corresponding b-collapse
prop. Note we use b-collapse
's v-model
to bind its visible
prop, which keeps the item's visible
prop in sync with the actual visibility state.
<!-- child.vue -->
<script>
export default {
data() {
return {
inputs: [
{
id: 1,
visible: false,
}, 👆
],
}
},
methods: {
addElement() {
this.inputs.push({ id: ++this.id, visible: false })
} 👆
}
}
</script>
<template>
⋮ 👇
<b-collapse v-model="element.visible" ⋯>
<div>Here is Element {{ index + 1 }}</div>
</b-collapse>
</template>
Add a watcher on the collapsed
prop in the child. This watcher will set each element's visible
prop to false
only when collapsed
is true
:
// child.vue
export default {
watcher: {
collapsed(collapsed) {
if (collapsed) {
this.inputs.forEach(input => input.visible = false)
}
},
}
}
To ensure each element's ID is globally unique in the context of the parents, incorporate the parent ID into the child IDs:
<!-- child.vue -->
<div v-for="(element, index) in inputs" :key="element.id">
<b-button v-b-toggle="'Element' + idParent + '.' + element.id" ⋯>
⋯ 👆
</b-button>
<b-collapse :id="'Element' + idParent + '.' + element.id" ⋯>
⋯ 👆
</b-collapse>
</div>
In the parent's addNewItem()
, add a collapsed
property. We'll bind each child's collapsed
prop to this new property, and toggle it upon a button-click:
<!-- parent.vue -->
<script>
export default {
data() {
return {
inputs: [
{
id: 1,
collapsed: false,
}, 👆
],
}
},
methods: {
addNewItem() {
this.inputs.push({ id: ++this.id, collapsed: false })
} 👆
}
}
</script>
<template>
â‹®
<div v-for="(item, index) in inputs" :key="item.id">
<b-button @click="item.collapsed = !item.collapsed">
⋯ 👆
</b-button>
<Child :idParent="item.id" :collapsed="item.collapsed" />
</div> 👆
</template>
Upvotes: 6