0
votes

Following Bootstrap Vue documentation, I've following code:

<template>
  <div>
    <b-table :items="items" :fields="fields" striped responsive="sm">
      <template #cell(show_details)="row">
        <b-button size="sm" @click="row.toggleDetails" class="mr-2">
          {{ row.detailsShowing ? 'Hide' : 'Show'}} Details
        </b-button>

        <!-- As `row.showDetails` is one-way, we call the toggleDetails function on @change -->
        <b-form-checkbox v-model="row.detailsShowing" @change="row.toggleDetails">
          Details via check
        </b-form-checkbox>
      </template>

      <template #row-details="row">
        <b-card>
          <b-row class="mb-2">
            <b-col sm="3" class="text-sm-right"><b>Age:</b></b-col>
            <b-col>{{ row.item.age }}</b-col>
          </b-row>

          <b-row class="mb-2">
            <b-col sm="3" class="text-sm-right"><b>Is Active:</b></b-col>
            <b-col>{{ row.item.isActive }}</b-col>
          </b-row>

          <b-button size="sm" @click="row.toggleDetails">Hide Details</b-button>
        </b-card>
      </template>
    </b-table>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        fields: ['first_name', 'last_name', 'show_details'],
        items: [
          { isActive: true, age: 40, first_name: 'Dickerson', last_name: 'Macdonald' },
          { isActive: false, age: 21, first_name: 'Larsen', last_name: 'Shaw' },
          {
            isActive: false,
            age: 89,
            first_name: 'Geneva',
            last_name: 'Wilson',
            _showDetails: true
          },
          { isActive: true, age: 38, first_name: 'Jami', last_name: 'Carney' }
        ]
      }
    }
  }
</script>

Full example could be found here.

According to this example, if I click Show Details button on each of the row it will show its respective row detail, but I want it to close all previous rows upon clicking it and only open details of the currently clicked row.

I know that looping through rows and setting detailsShowing to false can solve it like below:

this.rownames.forEach(item => {
  this.$set(item, 'detailsShowing', false)
})

but I don't know how to do it. Thank You.

2

2 Answers

1
votes

I feel the accepted answer is a bit over engineered, so I want to suggest what I think is a simpler solution.

This works by saving the "currently" open row in a variable, and setting _showDetails on it to false if another row is opened. This way we avoid having to do any sort of loops.

new Vue({
  el: "#app",
  data() {
    return {
      detailsRow: null,
      items: [
        { age: 40, first_name: "Dickerson", last_name: "Macdonald" },
        { age: 21, first_name: "Larsen", last_name: "Shaw" },
        { age: 89, first_name: "Geneva", last_name: "Wilson" },
        { age: 38, first_name: "Jami", last_name: "Carney" }
      ]
    };
  },
  methods: {
    onRowClicked(item) {
      const { detailsRow } = this
      if (detailsRow && detailsRow !== item) {
        detailsRow._showDetails = false;
      }

      this.$set(item, "_showDetails", !item._showDetails);
      this.detailsRow = item;
    }
  }
});
<link type="text/css" rel="stylesheet" href="https://unpkg.com/bootstrap/dist/css/bootstrap.min.css" />
<link type="text/css" rel="stylesheet" href="https://unpkg.com/[email protected]/dist/bootstrap-vue.min.css" />
<script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/bootstrap-vue.min.js"></script>

<div id="app">
  <b-table :items="items" @row-clicked="onRowClicked">
    <template #row-details="{ item }">
      <pre>{{ item }}</pre>
    </template>
  </b-table>
</div>
0
votes

Add a new data property called visibleRow and set it to null.

Then create a computed getter that returns your items but has the _showDetails property set. The value should be false by default unless visibleRow matches the item:

computed: {
  tableItems () {
    return this.items.map((item) => {
      return Object.assign({}, item, {
        _showDetails: this.visibleRow && this.visibleRow.first_name === item.first_name && this.visibleRow.last_name === item.last_name
      })
    })

  }
}

I've taken some liberties in determining what makes your rows unique but you're free to use whatever you want in the above comparison

Create a new method and modify your row click function to set the visibleRow on toggle:

methods: {
  setVisibleRow (row) {
    this.$set(this, 'visibleRow', row)
  }
}

Update your click method:

@click="setVisileRow(row.item._showDetails ? null : row.item)"

Finally, update your items binding on b-table:

<b-table :items="tableItems"