简体   繁体   中英

bootstrap-vue b-table: keep expanded rows expanded on table reload

the expand/collapse part of this works just fine.

Right now I am using javascript startInterval() to reload the table every 2 seconds. Eventually this will be moving to web sockets.

In general, as part of the table load/reload, the system checks to see if it should display the icon " ^ " or " v " in the details column by checking row.detailsShowing, this works fine.

getChevron(row, index) {
 if (row.detailsShowing == true) {     
   return "chevronDown";
 }
   return "chevronUp";
}

When the user selects the " ^ " icon in the relationship column, @click=row.toggleDetails gets called to expand the row and then the function v-on:click="toggleRow(row)" is called to keep track of which row the user selected. This uses a server side system generated guid to track.

Within 2 seconds the table will reload and the row collapses. On load/reload, in the first column it loads, relationship, I call a function checkChild(row), to check the row guid against my locally stored array, to determine if this is a row that should be expanded on load.

<template #cell(relationship)="row"> {{checkChild(row)}} <\template>

if the row guid matches one in the array I try setting

checkChild(row){
  var idx = this.showRows.indexOf( row.item.id);
    if(idx > -1){
     row.item.detailsShowing = true;
     row.rowSelected = true;
     row.detailsShowing == true
     row._showDetails = true;
   }
}

and I am able to see that i have found match, but none of those variables set to true keeps the expanded row open, the row always collapses on reload

anyone have any ideas as to how i can make the row(s) stay open on table reload?

The issue with your code is because of a Vue 2 caveat. Adding properties to objects after they've been added to data will not be reactive. To get around this you have to utilize Vue.set .

You can read more about that here .

However, calling a function like you are doing in the template seems like bad practice. You should instead do it after fetching your data, or use something like a computed property to do your mapping.

Here's two simplified examples.

Mapping after API call

{
  data() {
    return {
      items: [],
      showRows: []
    }
  },
  methods: {
    async fetchData() {
      const { data } = await axios.get('https://example.api')
      foreach(item of data) {
        const isRowExpanded = this.showRows.includes(item.id);
        item._showDetails = isRowExpanded;
      }
      this.items = data;
    }
  }
}

Using a computed

{
  computed: {
    // Use `computedItems` in `<b-table :items="computedItems">`
    computedItems() {
      const { items, showRows } = this;
      return items.map(item => ({
        ...item, 
        _showDetails: .showRows.includes(item.id)
      }))
    }
  },
  data() {
    return {
      items: [],
      showRows: []
    }
  },
  methods: {
    async fetchData() {
      const { data } = await axios.get('https://example.api')
      this.items = data;
    }
  }
}

For a more complete example, check the snippet below.

 const { name, datatype, image } = faker; const getUser = () => ({ uuid: datatype.uuid(), personal_info: { first_name: name.firstName(), last_name: name.lastName(), gender: name.gender(), age: Math.ceil(Math.random() * 75) + 15 }, avatar: image.avatar() }); const users = new Array(10).fill().map(getUser); new Vue({ el: "#app", computed: { computed_users() { const { expanded_rows, users } = this; return users.map((user) => ({...user, _showDetails: expanded_rows[user.uuid] })); }, total_rows() { const { computed_users } = this; return computed_users.length; } }, created() { this.users = users; setInterval(() => { users.push(getUser()); this.users = [...users]; }, 5000); }, data() { return { per_page: 5, current_page: 1, users: [], fields: [{ key: "avatar", class: "text-center" }, { key: "name", thClass: "text-center" }, { key: "personal_info.gender", label: "Gender", thClass: "text-center" }, { key: "personal_info.age", label: "Age", class: "text-center" } ], expanded_rows: {} }; }, methods: { onRowClicked(item) { const { expanded_rows } = this; const { uuid } = item; this.$set(expanded_rows, uuid, ;expanded_rows[uuid]); } } });
 <link href="https://unpkg.com/bootstrap@4.5.3/dist/css/bootstrap.min.css" rel="stylesheet" /> <link href="https://unpkg.com/bootstrap-vue@2.21.2/dist/bootstrap-vue.css" rel="stylesheet" /> <script src="https://unpkg.com/vue@2.6.12/dist/vue.min.js"></script> <script src="https://unpkg.com/bootstrap-vue@2.21.2/dist/bootstrap-vue.js"></script> <script src="https://unpkg.com/faker@5.5.3/dist/faker.min.js"></script> <div id="app" class="p-3"> <b-pagination v-model="current_page":per-page="per_page":total-rows="total_rows"> </b-pagination> <h4>Table is refresh with a new item every 5 seconds.</h4> <h6>Click on a row to expand the row</h6> <b-table:items="computed_users":fields="fields" bordered hover striped:current-page="current_page":per-page="per_page" @row-clicked="onRowClicked"> <template #cell(avatar)="{ value }"> <b-avatar:src="value"></b-avatar> </template> <template #cell(name)="{ item: { personal_info: { first_name, last_name } }}"> {{ first_name }} {{ last_name }} </template> <template #row-details="{ item }"> <pre>{{ item }}</pre> </template> </b-table> </div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM