I created functionality for the collapse where inside the body table, and there is the "+" add button, when I click on it it adds new collapse(another) with content and the I want to display the name of data row for example "Iphone" and appears new collapse with "Iphone" title/name.
It works great but I have issue, when I add, the title of created collapse is: "object MouseEvent"
CollapseSection.vue
<template>
<div class="accordion" role="tablist">
<b-button block v-b-toggle.accordion-1 class="collapse-btn" align-h="between">
{{ selectText }}
<b-icon :icon="visible ? 'caret-down' : 'caret-up'" class="icon"></b-icon>
</b-button>
<b-card no-body class="mb-1">
<b-collapse id="accordion-1" v-model="visible" accordion="my-accordion" role="tabpanel">
<SearchField></SearchField>
<b-card-body>
<!-- CONTENT WOULD APPEAR INSIDE THIS SLOT -->
<slot name="content" :addItem="addItem">
</slot>
</b-card-body>
</b-collapse>
</b-card>
<!-- DYNAMIC CONTENT COLLAPSE WHEN CLICK ON ADD BUTTON -->
<div v-for="(item, index) in items" :key="index">
<b-button block v-b-toggle="'accordion-' + (index + 2)" class="collapse-btn">
{{ item.name }}
<b-icon :icon="visible ? 'caret-down' : 'caret-up'" class="icon"></b-icon>
</b-button>
<b-card no-body class="mb-1">
<b-collapse :id="'accordion-' + (index + 2)" accordion="my-accordion" role="tabpanel">
<b-card-body>
<!-- CONTENT WOULD APPEAR INSIDE THIS SLOT -->
<slot name="createdContent">
</slot>
</b-card-body>
</b-collapse>
</b-card>
</div>
</div>
</template>
<script>
import SearchField from "@/components/UI/SearchField.vue";
export default {
name: "CollapseButton",
components: {SearchField},
props: {
selectText: {
type: String,
default: () => "Select",
},
},
data() {
return {
isConfiguring: false,
configuringItem: null,
items: [],
visible: false,
}
},
methods: {
addItem(name) {
const item = { name };
this.items.push(item);
this.isConfiguring = true;
this.configuringItem = item;
this.$emit('item-added', item);
}
},
}
</script>
DataTable.vue
<template>
<tbody>
<tr v-for="(item, itemIndex) in data" :key="itemIndex">
<td>
<slot></slot>
</td>
<td v-for="(label, labelIndex) in labels" :key="labelIndex">
{{ item[label.field] }}
</td>
</tr>
</tbody
</template>
<script>
export default {
name: "DataTable",
components: {ActionColumn},
props: {
labels: {
type: Array,
required: true,
},
data: {
type: Array,
required: true,
},
},
methods: {
addItem(name) {
this.$emit('add-item', name);
}
}
}
</script>
NewLab.vue
<CollapseSection select-text="Select Images">
<template #content="{ addItem }">
<DataTable :labels="labels" :data="data" :showAdd="true">
<b-icon icon="plus" class="add-btn" @click="addItem(data.name)">
</b-icon>
</DataTable>
</template>
<template #createdContent>
<CollapseTabContent>
</CollapseTabContent>
</template>
</CollapseSection>
<script>
const labels = [
{text: "Name", field: 'name'},
{text: "Description", field: 'description'},
]
const data = [
{name: 'Windows 1', description: 'Password Cracking'},
{name: 'Windows 13', description: 'SIEM and MISP machine'},
{name: 'Windows 15', description: 'AD auditing lab'},
{name: 'Windows 31', description: 'Threat Hunting and Investigation'},
];
export default {
name: "NewLab",
components: {DataTable, CollapseSection},
data() {
return {
labels: labels,
data: data,
};
},
</script>
SOLVED. I tried all possible solutions and nothing helped me. I asked GPT, different QNA forums also telegram channels with the VueJS community. I did not use any other technologies like VueX, etc. What I've done to solve the problem, First of all, I separated the Dynamic content of Collapse into a separate component DynamicCollapse.vue
<template>
<!-- DYNAMIC CONTENT COLLAPSE WHEN CLICK ON ADD BUTTON -->
<div>
<div v-for="(collapseItem, index) in dynamicCollapses" :key="index">
<b-button block
v-b-toggle="'accordion-' + (index + 2)"
class="collapse-btn d-flex justify-content-between align-items-center"
align-h="between"
>
{{ collapseItem.name }}
<b-icon
:icon="isVisible[index + 1] ? 'caret-down' : 'caret-up'"
class="icon justify-content"
></b-icon>
</b-button>
<b-card no-body class="mb-1">
<b-collapse
:id="'accordion-' + (index + 2)"
v-model="isVisible[index + 1]"
accordion="my-accordion"
role="tabpanel"
>
<b-card-body>
<slot name="createdContent" :item="collapseItem.content"></slot>
</b-card-body>
</b-collapse>
</b-card>
</div>
</div>
</template>
<script>
export default {
name: "DynamicCollapse",
items: [],
props: {
dynamicCollapses: {
type: Array,
default: () => []
},
},
data() {
return {
isVisible: [],
};
},
}
</script>
After that, I assumed not to pass the add button as a slot into DataTable
<!-- A dynamic column for add button -->
<template #cell(first)="data" v-if="showFirstColumn">
<b-icon icon="plus" class="add-btn" @click="addItemToDynamicCollapse(data.item.name)"></b-icon>
</template>
here is the method of DataTable.vue
methods: {
addItemToDynamicCollapse(name) {
this.$emit("add-to-dynamic-collapse", name);
},
and finally in the parent component
<CollapseSection select-text="Select Available Cloud Instance" collapse-id="instance">
<template #content>
<DataTable :fields="labels" :items="data" :showFirstColumn="true" @add-to-dynamic-collapse="addDynamicCollapse"/>
</template>
<template #createdContent>
<CollapseTabContent></CollapseTabContent>
</template>
</CollapseSection>
<DynamicCollapse :dynamic-collapses="dynamicCollapses">
<template #createdContent="{ item }">
<CollapseTabContent :data="item"></CollapseTabContent>
</template>
</DynamicCollapse>
and inside the parent component in section pass the data and method(I will refactor it in the future)
data() {
return {
dynamicCollapses: [],
};
},
methods: {
addDynamicCollapse(name) {
this.dynamicCollapses.push({
name: name,
content: {} // Add your content here
});
}
},
I spent a week solving it by reading and gaining a lot of information about the slots, data, scoped slots, etc. So I think this answer would help you.