0

I'm using the b-table from BootstrapVue with pagination. However, whenever I change pages, the items received from my REST API do not display, even though they are present. I have added a watcher to detect changes in the items array, and the console inside the watcher works as expected. The first page displays the items correctly, but subsequent pages do not. However, if I go back to the first page, the previously empty b-table loads the items.

After researching, I found that this is a known limitation:

b-table doesn't always know if the items being replaced (specifically when using external pagination) are from the same table or if the items array changes (i.e., to new data altogether). It must clear the selected items array whenever anything changes the table's context (sorting, filtering, pagination, table refresh, etc.).

My Current Implementation:

<b-table 
    v-if="showTable" 
    id="my-table1" 
    :items="tableItems" 
    :fields="fields" 
    :busy="isBusy"
    :per-page="limit" 
    :current-page="currentPage" 
    stacked="md" 
    table-class="padding"
    :tbody-tr-class="rowClass" 
    show-empty 
    small 
    responsive 
    hover 
    borderless
    selectable
>
</b-table>

Script:

props: {
   fields: {
       type: Array,
       default: () => []
   },
   items: {
       type: Array,
       default: () => []
   },
   totalRows: {
       type: Number,
       default: 0
   },
   isBusy: {
       type: Boolean,
       default: false
   },
},
data() {
    return {
        currentPage: 1,
        limit: 5,
        tableItems: [],
        selectedRows: [],
    };
},
watch: {
     items: {
        handler(newItems) {
        console.log("\n \n items changed", newItems);
        this.updateTableItems(newItems);
    },
  },
},
methods: {
    updateTableItems(newItems) {
           this.tableItems = [];
           this.$nextTick(() => {
                this.tableItems = [...newItems];
       });
    },
    changePage(page) {
        this.currentPage = page;
        this.$emit("pageChange", (page - 1) * this.limit, this.limit);
    }
}

Issue:

  • When switching pages items are not displaying.

How can I persist pagination in b-table? Any guidance or workaround would be greatly appreciated!

1 Answer 1

0

As you've already found, it's not something that the component supports.

Instead what you can do is do the selection logic yourself. Handling the state outside of the table, and opting out of the built-in system.

This way the state wont be cleared when the table items changes.

new Vue({
  el: '#app',
  computed: {
    selectedRows() {
      return this.items.filter(item => item.selected)
    }
  },
  data() {
    return {
      fields: [{
          key: "selected"
        },
        {
          key: "id",
          sortable: true
        }
      ],
      items: [],
      perPage: 50,
      currentPage: 1
    }
  },
  methods: {
    clearSelected() {
      this.selectedRows.forEach((item) => {
        this.$delete(item, 'selected')
      })
    },
    tbodyRowClass(item) {
      /* Style the row as needed */
      if (item.selected) {
        return ["b-table-row-selected", "table-primary", "cursor-pointer"]
      } else {
        return ["cursor-pointer"]
      }
    },
    rowClicked(item) {
      if (item.selected) {
        this.$set(item, 'selected', false)
      } else {
        this.$set(item, 'selected', true)
      }
    }
  },
  created() {
    for (let i = 1; i < 5000; i++) {
      this.items.push({
        id: i
      })
    }
  }
})
<script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/bootstrap-vue.js"></script>
<link type="text/css" rel="stylesheet" href="https://unpkg.com/[email protected]/dist/css/bootstrap.min.css" />
<link type="text/css" rel="stylesheet" href="https://unpkg.com/[email protected]/dist/bootstrap-vue.min.css" />

<div id="app">
  <b-container>
    <b-btn class="float-right" :disabled="selectedRows.length === 0" @click="clearSelected">
      Clear selection
    </b-btn>

    <b-pagination :per-page="perPage" v-model="currentPage" :total-rows="items.length"></b-pagination>
    Amount of items selected: {{ selectedRows.length }}

    <b-table :items="items" :fields="fields" :per-page="perPage" :current-page="currentPage" @row-clicked="rowClicked" :tbody-tr-class="tbodyRowClass" primary-key="id">
      <template v-slot:cell(selected)="{ item, field: { key } }" >
        <b-checkbox v-model="item[key]"></b-checkbox>
      </template>
    </b-table>
  </b-container>
</div>

Sign up to request clarification or add additional context in comments.

4 Comments

Thank you, Hiws, and thanks for your time. Actually, I made a mistake in my question. The b-table loads its first-page items without any issues. However, when I switch to the second page, even though the items array is present, the b-table doesn’t display it.
You can see that my script contains a watcher that detects changes in the items array. I also added a console log to check the content of the updated items array. The data appears to be correct, but the b-table doesn’t display the updated data. The same issue occurs on subsequent pages. However, if I go back to the first page, the table displays the items correctly.
Sounds like your tableItems only contains the items for a single page, but you're changing currentPage. So it sounds like you just want to remove currentPage from the table.
I also think it would've been better to ask a new question instead of editing your post to something completely different.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.