Displaying multiple bootstrap VueJS tables based on response from API

筅森魡賤 提交于 2020-06-17 13:09:07

问题


I am in the process of using bootstrap-vue table. Currently, my entire data resides in one table. Let's assume there are 10 rows in this table, and the first 5 rows contain value A in the first column while the next 5 rows contain value B in the first column.

What I want is, instead of having a single table containing complete data, I divide this table, so that on my page will appear two tables. The first table would contain all rows with values A and the second table would contain all rows with values B. In reality, I would have a lot of these unique values, so let's say, if I have 10 such values, I want 10 such individual tables based on these values. Is this possible to do?

Another idea could be, that if above is not possible, can I have collapsible rows? I am not talking about the More Details functionality, but rather, when I click on the A, all rows with value A would appear in the same table each appearing as a row in the table.

I was initially thinking of having rows that can span columns (Having grouped rows in bootstrap Vue table) but unfortunately, that is not supported by bootstrap vue-js table yet.


回答1:


You can do this by utilizing a computed property that splits your array up into groups.

This computed property will return a object, that contains a key which will be the value you're grouping on, and the value will be an array containing all items in that group.

/* Example structure that the computed property will return */
{
  A: [],
  B: [],
  C: []
}

You can then use a v-for to look each key in the groupedItems

<!-- 
  groupedItems is the computed property, containing the structure shown above.
  Will create a new table for each type/key in the `groupedItems` property.
-->
<div v-for="(group, type) in groupedItems">
  <b-table :fields="fields" :items="group"><b-table>
</div>

Example snippet:

A fairly basic example, which just display a header of the type and the table underneath.

/* Generate some random example data */
const types = ['A', 'B', 'C']
const items = [];
for(let i = 0; i < 15; i++) {
  items.push({
    type: types[i % 3],
    id: i + 1,
    random: Math.random()
  })
}

new Vue({
  el: '#app',
  computed: {
    groupedItems() {
      const groups = {};
      
      this.items.forEach(item => {
        if(groups[item.type]) {
          groups[item.type].push(item);
        } else {
          groups[item.type] = [item];
        }
      });

      return groups;
    }
  },
  data() {
    return {
      items: items,
      fields: ['type', 'id', 'random']
    }
  }
})
<link href="https://unpkg.com/bootstrap@4.5.0/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://unpkg.com/bootstrap-vue@2.15.0/dist/bootstrap-vue.css" rel="stylesheet" />

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.js"></script>
<script src="https://unpkg.com/bootstrap-vue@2.15.0/dist/bootstrap-vue.js"></script>


<div id="app">
  <div v-for="(items, type) in groupedItems">
    <h2>Type: {{ type }}</h2>
    <b-table :fields="fields" :items="items">
      <template #cell(type)="{ value }">
        Type: {{ value }}
      </template>
    </b-table>
  </div>
</div>

Example utilizing an accordion

This example utilizes an accordion, to allow each group to be opened/closed. Accoridon's only allow one group to be open at a type. If you don't want this , you can remove accordion="table-accordion" from the b-collapse so multiple can be opened at the same time.

/* Generate some random example data */
const types = ['A', 'B', 'C']
const items = [];
for(let i = 0; i < 15; i++) {
  items.push({
    type: types[i % 3],
    id: i + 1,
    random: Math.random()
  })
}

new Vue({
  el: '#app',
  computed: {
    groupedItems() {
      const groups = {};

      this.items.forEach(item => {
        if(groups[item.type]) {
          groups[item.type].push(item);
        } else {
          groups[item.type] = [item];
        }
      });

      return groups;
    }
  },
  data() {
    return {
      items: items,
      fields: ['type', 'id', 'random']
    }
  }
})
<link href="https://unpkg.com/bootstrap@4.5.0/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://unpkg.com/bootstrap-vue@2.15.0/dist/bootstrap-vue.css" rel="stylesheet" />

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.js"></script>
<script src="https://unpkg.com/bootstrap-vue@2.15.0/dist/bootstrap-vue.js"></script>


<div id="app">
  <b-card no-body class="mb-1" v-for="(group, type) in groupedItems">
    <b-card-header header-tag="header" class="p-0" role="tab">
      <b-button block v-b-toggle="`accordion-${type}`" variant="primary">
        Type {{ type }}
      </b-button>
    </b-card-header>
    <b-collapse :id="`accordion-${type}`" accordion="table-accordion" role="tabpanel">
      <b-table :fields="fields" :items="group"></b-table>
    </b-collapse>
  </b-card>
</div>

Additional example based on request in comments.

You can easily add another level by doing the same thing again, but nesting it one level deeper.

/* Generate some random example data */
const types = ['A', 'B', 'C']
const items = [];
for(let i = 0; i < 30; i++) {
  items.push({
    type: types[i % 3],
    group: i % 9,
    id: i + 1,
    random: Math.random()
  })
}

new Vue({
  el: '#app',
  computed: {
    groupedItems() {
      const groups = {};

      this.items.forEach(item => {
        if(!groups[item.type]) groups[item.type] = {};

        if(groups[item.type][item.group]) {
          groups[item.type][item.group].push(item);
        } else {
          groups[item.type][item.group] = [item];
        }
      });

      return groups;
    }
  },
  data() {
    return {
      items: items,
      fields: ['type', 'id', 'random']
    }
  }
})
<link href="https://unpkg.com/bootstrap@4.5.0/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://unpkg.com/bootstrap-vue@2.15.0/dist/bootstrap-vue.css" rel="stylesheet" />

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.js"></script>
<script src="https://unpkg.com/bootstrap-vue@2.15.0/dist/bootstrap-vue.js"></script>


<div id="app">
  <b-card no-body class="mb-4" v-for="(groups, type) in groupedItems">
    <b-card-header header-tag="header" class="p-0" role="tab">
      <b-button block v-b-toggle="`accordion-${type}`" variant="primary">
        Type {{ type }}
      </b-button>
    </b-card-header>
    <b-collapse :id="`accordion-${type}`" visible role="tabpanel">
      <b-card no-body v-for="(items, group) in groups">
        <b-card-header header-tag="header" class="p-0" role="tab">
          <b-button block v-b-toggle="`accordion-group-${group}`" variant="secondary">
            Type {{ group }}
          </b-button>
        </b-card-header>
        <b-collapse :id="`accordion-group-${group}`"  :accordion="`table-accordion-${type}`" role="tabpanel">
          <b-table :fields="fields" :items="items"></b-table>
        </b-collapse>
      </b-card>
    </b-collapse>
  </b-card>
</div>


来源:https://stackoverflow.com/questions/62288939/displaying-multiple-bootstrap-vuejs-tables-based-on-response-from-api

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!