Pass agruments/data into the methods for displaying the name in new created component in VueJS

53 Views Asked by At

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"enter image description here

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>
1

There are 1 best solutions below

0
Temka On BEST ANSWER

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.