pagination and filter separately running / Vue

2019-06-24 13:52发布

I fetch and do pagination on the data, no problem with that. But when I try to filter the data, the pagination not working with the filtered data. Still displaying next pages at bottom. And when I go(for example) page 2 there is no data in page two. Because I filtered it already. How can I fix this problem? Thank you!

Index Component

Data(){
    meta_data: {
          last_page: null,
          current_page: 1,
          prev_page_url: null
     }
},
methods: {
    fetchEstates(page = 1){
        axios.get('/ajax', {
            params: {
                page
            }}).then((response) => {
                // console.log(response);
                this.estates = response.data.data;
                this.insertMarkers();
                this.meta_data.last_page = response.data.last_page;
                this.meta_data.current_page = response.data.current_page;
                this.meta_data.prev_page_url = response.data.prev_page_url;
        });
    },
},

computed: {
    one: function () {
        let filteredStates = this.estates.filter((estate) => {
            return (this.keyword.length === 0 || estate.address.includes(this.keyword)) &&
            (this.rooms.length === 0 || this.rooms.includes(estate.rooms)) &&
            (this.regions.length === 0 || this.regions.includes(estate.region))});

            if(this.sortType == 'price') {
                filteredStates = filteredStates.sort((prev, curr) => prev.price - curr.price);
            }
            if(this.sortType == 'created_at') {
                filteredStates = filteredStates.sort((prev, curr) => Date.parse(curr.created_at) - Date.parse(prev.created_at));
            }

            filteredStates = filteredStates.filter((estate) => { return estate.price <= this.slider.value});
            filteredStates = filteredStates.filter((estate) => { return estate.extend <= this.sliderX.value});
            filteredStates = filteredStates.filter((estate) => { return estate.m2_price <= this.sliderT.value});

            return filteredStates;
    },
}
<pagination
      :meta_data="meta_data"
      v-on:next="fetchEstates">
</pagination>

Pagination Component

    props: ['meta_data'],
    methods: {
        next(page) {
            this.$emit('next', page);
        }
    }
}
    <nav>
         <ul class="pagination pagination-lg">
             <li class="page-item"
                 :class="{ 'disabled': meta_data.prev_page_url === null }">
                 <a href="#"
                     class="page-link"
                     @click="next(meta_data.current_page-1)">
                     &laquo;
                 </a>
             </li>
             <li class="page-item"
                 v-for="page in meta_data.last_page"
                 :key="page"
                 :class="{ 'active':meta_data.current_page === page }">
                 <a href="#"
                     @click.prevent="next(page)"
                     class="page-link">
                     {{ page }}
                 </a>
             </li>
             <li class="page-item"
                 :class="{ 'disabled': meta_data.current_page === meta_data.last_page }">
                <a  href="#"
                     class="page-link"
                     @click="next(meta_data.current_page+1)">
                     &raquo;
                </a>
             </li>
        </ul>
    </nav>

2条回答
等我变得足够好
2楼-- · 2019-06-24 14:31

Hello I'm not sure you are going about this in the best way. I have recently done something similar. Below is my simplified code:

HTML:

<div id="app">
    <table>
      <thead>
       <tr>
      <th>Index</th>
      <th>Item</th>
    </tr>
  </thead>
  <tbody>
    <tr v-for="item, index in filterItems" v-if="index >= pagestart && index <= pageend">
      <td>{{index}}</td>
      <td>{{item}}</td>
    </tr>
  </tbody>
</table>
<div class="col-lg-12">
    <ul class="pagination" style="padding:20px;">
        <li><a @click="pagination(pagecurrent - 1)">‹</a></li>
        <li v-for="index in pagipages" @click="pagination(index)" :class="{active:index == pagecurrent}"><a>{{index}}</a></li>
        <li><a @click="pagination(pagecurrent + 1)">›</a></li>
    </ul>
</div>

VUE:

new Vue({
  el: '#app',
    data () {
        return {
            items: [],
            pagecurrent: 1,
            pagestart: 0,
            pageend: 25,
            itemsperpage: 25,
        }
    },
    methods:{
        pagination: function pagination(index) {
            //This calculates the range of data to show depending on the selected page
            if (index > 0 && index <= this.pagipages) {
                this.pagecurrent = index;
                this.pagestart = (this.itemsperpage * index) - this.itemsperpage;
                this.pageend = (this.itemsperpage * index);
            }
        },
    },
    computed: {
        filterItems: function filterItems() {
            var filter = this.items;
            //Do Filtering here
            return filter;
        },
        pagipages: function pagipage() {
            //This calculates the amount of pages
            return Math.ceil(this.filterItems.length / this.itemsperpage);
        }
    },

    watch: {
        //This resets the data for when the filter is changed
        filterItems: function() {
            this.pagecurrent = 1;
            this.pagestart = 0;
            this.pageend = this.itemsperpage;
        }
    }
})
查看更多
一纸荒年 Trace。
3楼-- · 2019-06-24 14:35

You are doing it wrong you should send the data to backend/sql then filter them there. so you get the right last_page etc.

Anyway if you still want to filter them as its is, you will need to calculate the pages agen.

Here is a sample, so you could calculate how many pages in filteredStates and generate pages, you may already able to generate them but the calculation could help you.

Data(){
// you should use data only :) eg data:function()  { return  meta_data }
// but if this work for you i gusse its fine.
    meta_data: {
          totalPages: null,
          current_page: 1,
          pageSize: 20,// how many items exist per page
          pagedItems: [], // paged items eg when you click prev or next
          filteredData:[], // total items
          prevClass: "",
          nextClass: "",
          pages:[]
         
     }
},
methods: {
    // this will init the paginations and display the data
    getData: function(){
    // totalpages 
      this.meta_data.totalPages = Math.ceil(this.meta_data.filteredData.length / this.meta_data.pageSize);
       // items for the current selected Page
       this.meta_data.pagedItems = 
       this.meta_data.filteredData.slice(this.meta_data.pageSize * (this.meta_data.current_page -1),this.meta_data.pageSize);
       
       if (this.meta_data.current_page == this.meta_data.totalPages
       || this.meta_data.totalPages <=1)
           this.meta_data.nextClass = "disabled";
           else this.meta_data.nextClass = "";
           
      if (this.meta_data.current_page <=1)
           this.meta_data.prevClass = "disabled";
           else this.meta_data.prevClass = "";
           
           this.calPages();
     
    },
    
    toPage:function(page){
      this.meta_data.current_page = page;
      this.getData();
    },
    
    next: function(){
     if (this.meta_data.totalPages >= this.meta_data.current_page +1){
         this.meta_data.current_page++;
         this.getData();
         }
         
        return false;
    },
    
    prev: function(){
     if (this.meta_data.current_page -1 >=1 ){
          this.meta_data.current_page--;
          this.getData();
         }
         
        return false;
    },
    // this will generate [counter] pages each time you select a page.
    // I wrote this a long time ago for one of my application
    calPages: function(){
      if (this.meta_data.totalPages<=0)
          return false;
      var start = this.meta_data.current_page;
			var end = this.meta_data.current_page;
			var counter = 3;
      //If the page cannot be devised by counter enter the loop
			if ((start % counter != 0) && (end % counter != 0)) {
				//Get the next nearest page that is divisible by 5
				while ((end % counter) != 0) {
					end++;
				}
				//Get the previous nearest page that is divisible by counter
				while ((start % counter) != 0) {
					start--;
				}

			}
			//The page is divisible by counter so get the next counter pages in the pagination
			else {
				end += counter;
			}
			//We are on the first page
			if (start == 0) {
				  start++;
				  end++;
			}



			//We are on the last page
			if (end == this.meta_data.totalPages || end > this.meta_data.totalPages) {
				end = this.meta_data.totalPages ;
			}

			if (start == this.meta_data.current_page && start > 1)
				start--;

			while (end - start < counter && end - start > 0)
				start--;


			if (start <= 0)
				start = 1;

			while (end - start > counter)
				end--;
       var r =[];
       
       for (var i = start; i <= end; i++)
            r.push({ page:i, selected:(this.meta_data.current_page == i? "selected" : "") });
            
          this.meta_data.pages = r;
    }

    fetchEstates(page = 1){
        axios.get('/ajax', {
            params: {
                page
            }}).then((response) => {
                // console.log(response);
                this.estates = response.data.data;
                this.insertMarkers();
                //this.meta_data.last_page = response.data.last_page;
                //this.meta_data.current_page = response.data.current_page;
                //this.meta_data.prev_page_url = response.data.prev_page_url;
        });
    },
},

computed: {
    // dont see where you are calling this?
    one: function () {
        let filteredStates = this.estates.filter((estate) => {
            return (this.keyword.length === 0 || estate.address.includes(this.keyword)) &&
            (this.rooms.length === 0 || this.rooms.includes(estate.rooms)) &&
            (this.regions.length === 0 || this.regions.includes(estate.region))});

            if(this.sortType == 'price') {
                filteredStates = filteredStates.sort((prev, curr) => prev.price - curr.price);
            }
            if(this.sortType == 'created_at') {
                filteredStates = filteredStates.sort((prev, curr) => Date.parse(curr.created_at) - Date.parse(prev.created_at));
            }

            filteredStates = filteredStates.filter((estate) => { return estate.price <= this.slider.value});
            filteredStates = filteredStates.filter((estate) => { return estate.extend <= this.sliderX.value});
            filteredStates = filteredStates.filter((estate) => { return estate.m2_price <= this.sliderT.value});
            
this.meta_data.filteredData = filteredStates;
this. getData()// this will init the paginations and display the data 
return filteredStates;
    },
}
 <nav>
         <ul class="pagination pagination-lg">
             <li class="page-item"
                 :class="meta_data.prevClass">
                 <a href="#"
                     class="page-link"
                     v-on:click="prev">
                     &laquo;
                 </a>
             </li>
             <li class="page-item"
                 v-for="page in meta_data.pages" :key="page"
                 :class="page.selected">
                 <a href="#"
                     v-on:click="toPage(page.page)"
                     class="page-link">
                     {{ page.page }}
                 </a>
             </li>
             <li class="page-item" :class="meta_data.prevClass" v-on:click="next" >
                <a href="#"
                     class="page-link"
                     @click="next">
                     &raquo;
                </a>
             </li>
        </ul>
    </nav>

查看更多
登录 后发表回答