eddy1992's avatar

Pagination and ajax

Hi I am making an e commerce website and I have filter in my front end.

There are two types of filters to filter products :

  1. By brands
  2. By price

Now what I am doing right now is that when a user clicks on the brands filter check box an ajax call is fired and I fetch the brand ids and then I find all the products related to the brand ids.

my jquery ajax (Sorry I am very new with ajax )


 var brand_array = new Array();
      $('.filter-data-brands input').on('click',function(){
        if($(this).parent('label').hasClass('is-checked')){
            var dataValue = brand_array.pop($(this).data('value'));
        }
        else{
            var dataValue = brand_array.push($(this).data('value'));
        }
        
        
         
        $.ajax({
          url: '/filter',
           headers: {
             'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
          },
          type: 'post',
          data: {'brand_array': brand_array, 'price_array': price_array},
          success: function(data, status) {

             //console.log(data);
            if(data.status == "ok") {

                 $('.catalog-right__inner').html(data.html);
                // $('..promo-code').append('<span>'+data+'</span>')
            }
          },
          error: function(xhr, desc, err) {
            console.log(xhr);
            console.log("Details: " + desc + "\nError:" + err);
          }
        }); // end ajax
    });    
        

     var price_array = new Array();
      $('.filter-data-price input').on('click',function(){
        if($(this).parent('label').hasClass('is-checked')){
            var dataValue = price_array.pop($(this).data('value'));
        }
        else{
            var dataValue = price_array.push($(this).data('value'));
        }
        
         
        $.ajax({
          url: '/filter',
           headers: {
             'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
          },
          type: 'post',
          data: {'price_array': price_array, 'brand_array': brand_array},
          success: function(data, status) {

            if(data.status == "ok") {
                $('.catalog-right__inner').html(data.html);
            }
          },
          error: function(xhr, desc, err) {
            console.log(xhr);
            console.log("Details: " + desc + "\nError:" + err);
          }
        }); // end ajax
    }); 
    </script>

now it call my route method name filter

 Route::post('filter/', ['as' => 'filter', 'uses' => 'ProductsController@filter']);

Now my controller method filter ( I am just pasted the brands code as of now )


 elseif(array_key_exists("brand_array", $data)){
            
            $brandIds = $data['brand_array'];
            $products = Product::whereHas('brands', function($query) use ($brandIds)
            {
                $query->whereIn('brand_id', $brandIds);
            })->paginate(15);
            $productDetails = $this->prepareAllProductDetails($products);
            $html =  $this->createHtml($productDetails);
            if($html != null){
                return ['status' => 'ok', 'html' => $html];     
            }
        }
        else{

            $products = Product::where(['parent_product_id' => null])->paginate(15);
            $productDetails = $this->prepareAllProductDetails($products);
            $html =  $this->createHtml($productDetails);
            if($html != null){
                return ['status' => 'ok', 'html' => $html];     
            }

now createHtml creates a view and returns it


public function createHtml($productDetails)
    {
        $html =null;
        if($productDetails != null){

            foreach($productDetails as $details){
                    
            $html .= '<div class="product-block">';
            $html .= '<div class="product-block__inner">';
            $html .= '<a href="'. route('product.detail',$details['id']). '"/>';
            $html .= '<img src="'. url("get-image".'/'.$details["id"].'/'.$details["image"]).'" class="img-responsive" alt="Product" title="Product" width="136" height="193" />';
            $html .= '</a>';
            $html .= '<span class="product-block__off">';
            $html .= '<i class="fa fa-inr"></i> 15 <span class="product-block__off--inner">off</span>';
            $html .= '</span>';
            $html .= '<span class="product-list-icon"></span>';
            $html .= '<div class="product-block__details">';
            $html .= '<h2 class="product-name">';
            $html .= '<a href="#">' . $details['name'];
            $html .= '</a>';
            $html .= '</h2>';
            if($details['is_configurable_product']){
                if(isset($details['configurable_attributes'])){
                    $html .= '<div class="product-options">';
                    $html .= '<form>';
                    $html .= '<select>';
                    foreach($details['configurable_attributes'] as $attribute){
                        $html .= '<option>'.$attribute['value'].'</option>';
                     }
                    $html .= '</select>';
                    $html .= '</form>';
                    $html .= '</div>';
                }
                else{
                    $html .= '<div class="product-options">';
                    $html .= '<form>';
                    $html .= '<select>';
                    $html .= '<option>-- No Options Available --</option>';
                    $html .= '</select>';
                    $html .= '</form>';
                    $html .= '</div>';
                }
            }
            $html .= '<div class="price-cart-btn">';
            if(isset($details['configurable_attributes']) and $details['is_configurable_product']){
                 $html .= '<span class="product-new-price" id="product_mrp">';
                 $html .= '<i class="fa fa-inr"></i>'.$details['configurable_attributes'][0]['mrp'].'</span>';
                 $html .= '<span class="product-old-price" id="product_sale_price">';
                 $html .= '<i class="fa fa-inr"></i>'.$details['configurable_attributes'][0]['sale_price'].'</span>';
            }
            else{
                $html .= '<span class="product-new-price">';
                $html .= '<i class="fa fa-inr"></i>'.$details['mrp'].'</span>';
                $html .= '<span class="product-old-price">';
                $html .= '<i class="fa fa-inr"></i>'.$details['sale_price'].'</span>';
                $html .= '';
            }
            $html .= '<button type="button"></button>';
            $html .= '</div>';
            $html .= '</div>';
            $html .= '</div>';
            $html .= '</div>';
          }
        }  
      return $html;

    }

My question is how will I get a pagination after the ajax call , because after the ajax call the old pagination still exist and refreshes the page so I do not get the pagination.

my view which has the pagination


   <div class="pagination-outer">
                        <?php echo $products->render(); ?>
        </div>

How will I get the pagination related to the brands query I made in the filter method in the controller

0 likes
2 replies
ZetecVan's avatar

You would need to have some ajax to re-generate the pagination. I've not done this using ajax before but this is how I did it in VueJS. It may help. If you've not started learning vueJS, give it a go:

In the view, this shows the full 'grid' part of the page including the pagination.

<div v-if="!loading" class="col-lg-9 col-md-9">
            <h3 v-if="totalPages == 0 && loading == false">Nothing meets your selection. Try selecting another category.</h3>
            <div class="row">
            @include('attractions.grid')
            </div>
            <hr>
            <div class="text-center">
                <nav>
                    <ul class="pagination" v-if="totalPages > 0">
                        <li>
                            <a href="#" v-on="click: setPage(0)">
                                <span aria-hidden="true">&laquo;</span>
                            </a>
                        </li>
                        <li v-repeat="pageNumber: totalPages" v-class="active: currentPage === pageNumber">
                            <span>
                                    <a href="#" v-on="click: setPage(pageNumber)">@{{ pageNumber + 1 }}</a>
                                </li>
                            </span>
                            <li>
                                <a href="#" v-on="click: setPage(totalPages)">
                                    <span aria-hidden="true">&raquo;</span>
                                </a>
                            </li>
                    </ul>
                </nav>
            </div>
            <!-- end pagination-->
        </div>

and the vuejs attractions.js

Vue.http.headers.common['X-CSRF-TOKEN'] = document.querySelector('#token').getAttribute('value');

var globalattractions = [];

new Vue({
    el: '#att',
    data: {
    // some data here
    },

    ready: function() {
        this.getAttractions()
        this.loading = false

    },
    // Methods we want to use in our application are registered here
    methods: {
        getAttractions: function(type) {
            var self = this;
            if (window.type) this.type = window.type;
            this.$http.get('/api/places/' + this.type, function(attractions) {
                this.$set('attractions', attractions.data)
                this.currentPage = 0
                this.resultCount = attractions.data.length
                this.totalPages = Math.ceil(this.resultCount / this.itemsPerPage)
                this.attractions.forEach(function(attraction) {
                if('undefined' !== typeof attraction.location) {
                  attraction.showmarker = true
                    record = self.createRecord(attraction)
                    globalattractions.push(record)
                  }
                    
                })

            }.bind(this))

        },
        setPage: function(pageNumber) {
            this.currentPage = pageNumber
        },
        createRecord: function(attraction) {
            record = {
            // Some Code Here
            }
            return record;
        }
    },
    computed: {
        totalPages: function() {
            return Math.ceil(this.resultCount / this.itemsPerPage)
        }
    },
    filters: {
        paginate: function(list) {
            this.resultCount = list.length

            if (this.currentPage >= this.totalPages) {
                this.currentPage = Math.max(0, this.totalPages - 1)
            }
            var index = this.currentPage * this.itemsPerPage
            this.startPage = Math.max(0, this.currentPage - 3);
            this.endPage = Math.min(this.totalPages, this.startPage + 6);
            return list.slice(index, index + this.itemsPerPage)
        },

    }


})

So the getAttractions calculates the total number of pages based upon the number of results divided by items per page, then...

<li v-repeat="pageNumber: totalPages" v-class="active: currentPage === pageNumber">

repeats however many pages there are to do the pagination.

My site won't have any more than around 8 pages, so that will show 1 - 8. You may have to do it differently to calculate the pagination if it's more and you have to do 1 2 3 4 5 6 7 .. 10 20 like you see on some sites.

Hope that helps.

1 like

Please or to participate in this conversation.