1
votes

I have written the following code:

<div>
    <div id="app" class="container">
        <div class="grid">
            <article v-for="tool in tools">
                <div class="title">
                    <h3>{{capitalizeFirstLetter(tool.name)}}</h3>
                </div>
                <div class="description">
                    {{tool.description}}
                </div>
                <br>
                <div>
                    <toggle-button :value=tool.status color="#82C7EB" :width=100 :height=30 :sync="true" :labels="{checked: 'Following', unchecked: 'Unfollowing'}" @change="onChange(tool)"/>
                </div>
            </article>
        </div>
    </div>
</div>

Recently I started using Bootstrap-Vue. I'm trying to figure out how to add pagination on the bottom. I'm not sure how aria-controls works. My goal is to have 9 blocks of tools on each page. How should I add the pagination so I could move to the next 9 blocks of tools?

2

2 Answers

1
votes

Since it wasn't clear if you needed client-side pagination or serverside i made an example of both in the snippet.

For simplicity I've made it 3 per page, but you could change it to 9.

The first one gets the initial page on load, and then calls the API every time the page changes by using a watcher, that calls a method with the new page which then retrieves that place and replaces our old data with the new.

The second one loads all the data on page load, and instead slices the data array based on the per_page property, so that only the items for that page is shown. For this I've used a computed property which automatically updates based on the properties used inside it.

Both paginations have aria-controls defined with the id of the container of our page elements. This is used to tell screen readers what elements the pagination changes.

The classes row, col-*, border, mx-auto, h2 and text-center is classes used for styling and layout and isn't part of the actual solution, so you can freely change or remove them.

new Vue({
  el: '#app',
  computed: {
    pagination2CurrentItems() {
      const startIndex = (this.pagination2.current_page - 1) * this.pagination2.per_page;
      const endIndex = startIndex + this.pagination2.per_page;
      return this.pagination2.items.slice(startIndex, endIndex)
    }
  },
  created() {
    this.getPagination1Data()
    this.getPagination2Data()
  },
  filters: {
    capitalizeFirstLetter(value) {
      return value.charAt(0).toUpperCase() + value.slice(1)
    }
  },
  data() {
    return {
      pagination1: {
        items: [],
        per_page: 3,
        total_rows: 0,
        current_page: 1
      },
      pagination2: {
        items: [],
        per_page: 3,
        total_rows: 0,
        current_page: 1
      }
    }
  },
  methods: {
    getPagination1Data(page = 1) {
      fetch(`https://reqres.in/api/unknown?page=${page}&per_page=3`)
        .then((response) => {
          return response.json();
        })
        .then((data) => {
          this.pagination1.total_rows = data.total;
          this.pagination1.items = data.data;
        });
    },
    getPagination2Data() {
      /*  
        This endpoint only has 12 items total, 
        so this will get all in one call
      */
      fetch(`https://reqres.in/api/unknown?per_page=12`)
        .then((response) => {
          return response.json();
        })
        .then((data) => {
          this.pagination2.total_rows = data.total;
          this.pagination2.items = data.data;
        });
    }
  },
  watch: {
    'pagination1.current_page'(newPage) {
      this.getPagination1Data(newPage)
    }
  }
})
<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 href="https://unpkg.com/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://unpkg.com/[email protected]/dist/bootstrap-vue.css" rel="stylesheet"/>

<div id="app" class="container">
  <div id="tools_list_1" class="row">
    <div class="col-12 h2 text-center">
     Server pagination
    </div>
    <article class="col-3 mx-auto border" v-for="tool in pagination1.items">
      <div class="title">
        <h3>{{ tool.name | capitalizeFirstLetter }}</h3>
      </div>
      <div class="description">
        {{ tool.pantone_value }}
      </div>
    </article>
  </div>
  <div class="row mt-2">
    <div class="col-12">
      <b-pagination
        v-model="pagination1.current_page"
        :per-page="pagination1.per_page"
        :total-rows="pagination1.total_rows"
        aria-controls="tools_list_1"
        >
      </b-pagination>
    </div>
  </div>
  <div id="tools_list_2" class="row">
    <div class="col-12 h2 text-center">
      Client pagination
    </div>
    <article class="col-3 mx-auto border" v-for="tool in pagination2CurrentItems">
      <div class="title">
        <h3>{{ tool.name | capitalizeFirstLetter }}</h3>
      </div>
      <div class="description">
        {{ tool.pantone_value }}
      </div>
    </article>
  </div>
  <div class="row mt-2">
    <div class="col-12">
      <b-pagination
        v-model="pagination2.current_page"
        :per-page="pagination2.per_page"
        :total-rows="pagination2.total_rows"
        aria-controls="tools_list_2"
        >
      </b-pagination>
    </div>
  </div>
</div>
0
votes

If you are interested in server side pagination with url changes of query params (using vue-router in history mode) and you need browser history (back/forward) to work properly, you can check my answer to a similar question. I think it can be adapted to not use b-table.

Place pagination number in url Vuejs