Search code examples
vue.jspaginationcomputed-properties

How to make a proper pagination with Vuejs? Setter not defined error


Working on the pageNav for a personal app I am working on and cannot get the index to show properly.

I figure that making the pageIndexInner and itemsPerPageInner computed propetries was the best route, but when it comes to editing those, I need to also have a setter? I've looked into getters and setters, but am having a very hard time wrapping my head around it.

Without the computer properties, the click event works and I can make it all the way to the itemToal amount, but the index doesn't match up.

If you change the default pageIndex to 3, I want to see:

enter image description here

but this is what I'm actually seeing:

enter image description here

I'm just not sure where to go with all of this and any guidance would be greatly appreciated. Thank you

Codepen Link:https://codepen.io/LovelyAndy/pen/NWbjLGz?editors=1010

Vue Component code:

<template>
    <div class="_table-page-nav-wrapper">
    <div @click="back" :disabled="pageIndexInner === 0" class="_arrow-btn">
    <
    </div>
    <div class="_page-index-inner">
      {{ itemsTotal }} Total Items {{ pageIndexInnerStart}} - {{ itemsPerPageInnerStart }} Shown
    </div>
    
    <div @click="forward" class="_arrow-btn">
  >
    </div>
  </div>
</template>

<style lang="sass" scoped>
._table-page-nav-wrapper
  display: flex
  justify-content: center
  align-items: center
  div
    display: flex
    justify-content: center
    align-items: center

._arrow-btn
  width: 50px
  height: 50px
  border-radius: 4px
  box-shadow: 0 5px 5px rgba(0,0,0,0.2)

._page-index-inner
  width: 244px
  height: 50px
  border-radius: 4px
  box-shadow: 0 5px 5px rgba(0,0,0,0.2)
  margin: 0px 20px
</style>

<script>
export default {
  name: 'TablePageNavigation',
  props: {
    /**
     * passed values can be either 10 or 25 or 50
     */
    itemsPerPage: {
      type: Number,
      default: 10,
      validator: (prop) => [10, 25, 50].includes(prop),
    },
    pageIndex: {
      type: Number,
      default: 0,
    },
    itemsTotal: {
      type: Number,
      default: 100,
    },
  },
  data() {
    return {
      pageIndexInner: this.pageIndex,
      itemsPerPageInner: this.itemsPerPage,
    }
  },
  computed: {
    pageIndexInnerStart() {
      return this.pageIndex + this.itemsPerPage
    },
    itemsPerPageInnerStart() {
      return this.itemsPerPage + this.itemsPerPage
    },
  },
  methods: {
    back() {
      if (this.itemsPerPageInner > this.itemsPerPage) {
        this.itemsPerPageInner = this.itemsPerPageInner - this.itemsPerPage
        this.pageIndexInner = this.pageIndexInner - this.itemsPerPage
        const newIndex = this.pageIndexInner
        this.$emit('update:pageIndex', newIndex)
      }
      return
    },
    forward() {
      if (
        this.itemsPerPageInnerStart + this.itemsPerPage > this.itemsTotal ||
        this.PageIndexInnerStart + this.itemsPerPage > this.itemsTotal
      ) {
        return
      }
      this.pageIndexInnerStart = this.pageIndexInnerStart + this.itemsPerPage
      this.itemsPerPageInnerStart = this.itemsPerPageInnerStart + this.itemsPerPage
    },
  },
}
</script>

Solution

  • I commented on your related question earlier this morning, and decided to create an example based on my previous pagination implementation that I mentioned. I removed a lot of your calculations for a simpler approach. I didn't handle all scenarios such as if total items is not a multiple of items per page, but if you like what I did you can work that out on your own. Here is the code from my single file component that I developed in my Vue sandbox app, which uses Bootstrap 4.

    <template>
      <div class="table-page-navigation">
        <button class="btn btn-primary" @click="back" >Back</button>
    
        <span>
          {{ itemsTotal }} Total Items {{ pageFirstItem}} - {{ pageLastItem }} Shown
        </span>
    
        <button class="btn btn-secondary" @click="forward" >Forward</button>
      </div>
    </template>
    
    <script>
      export default {
        name: 'TablePageNavigation',
        props: {
          /**
           * passed values can be either 10 or 25 or 50
           */
          itemsPerPage: {
            type: Number,
            default: 10,
            validator: (prop) => [10, 25, 50].includes(prop),
          },
          itemsTotal: {
            type: Number,
            default: 100,
          },
        },
        data() {
          return {
            currentPage: 1,
          }
        },
        computed: {
          numPages() {
            return this.itemsTotal / this.itemsPerPage;
          },
          pageFirstItem() {
            return (this.currentPage - 1) * this.itemsPerPage + 1;
          },
          pageLastItem() {
            return this.currentPage * this.itemsPerPage;
          }
        },
        methods: {
          back() {
            if (this.currentPage > 1) {
              this.currentPage--;
            }
          },
          forward() {
            if (this.currentPage < this.numPages) {
              this.currentPage++;
            }
          },
        },
      }
    </script>