chilldsgn's avatar

Ajax pagination loads entire page

I am attempting to create ajax pagination using a "load more" button instead of Laravel's default pagination. Now, I've spent the past couple of days searching online for a solution, but everything is jquery and I am relatively new to javascript and Laravel. I'd prefer to avoid jquery, since I am trying to get better at working with vanilla javascript.

The index view paginates 4 items (for testing purposes at this point) and on each ajax request, I would like to render the next 4 rows.

My problem is, the ajax request renders the entire page instead of just the data from the database. What am I doing wrong in my code?

Controller:

public function ajax()
    {
        $products = Product::orderBy('title', 'asc')->paginate(4);    
        return $products;
    }

Javascript:

const container = document.querySelector('#sandbox-container');
const button = document.getElementById('load-stuff');
let url = button.getAttribute('href'); // http://127.0.0.1:8000/sandbox?page=2 

button.addEventListener('click', (event) => {
    event.preventDefault();
    const xhr = new XMLHttpRequest();
    xhr.open('GET', url);
    
    xhr.onload = function() {
        if (xhr.status === 200) {  
            container.insertAdjacentHTML('beforeend', xhr.responseText); // ouputs html of entire view      
            console.log(`This is the response: ${xhr.responseText}`);
        }
        else {
            console.log(`Request failed, this is the response: ${xhr.responseText}`);
        }
    };

    xhr.send();     
})

View: sandbox.blade.php

<div class="product-thumb-test-wrapper" id="sandbox-container">
    @foreach ($products as $product)
    <div>
      <p >{{ $product->title }}</p>
      <img src="/images/product/{{ $product->img }}" alt="{{ $product->title }}">
    </div>
  @endforeach   
</div> 
<div class="grid row" id="loaded-more"> 
</div> 
<div class="grid">
    {{ $products->links('vendor.pagination.default') }}            
</div>

I am not sure what I need to do in order to render the xhr.responseText as only the $products data? I've tried sending it as json data, but that returns null each time. I hope someone can help a noob out here, thanks in advance!

0 likes
2 replies
chilldsgn's avatar

OK so I changed my controller

public function sandbox(Request $request)
    {

        $products = Product::orderBy('title', 'asc')->paginate(4);

        $response = [
            'links' => [
                'next' => $products->nextPageUrl()
            ],
            'data' => $products
        ]; 

        if($request->ajax()){
            dd($response);
        }
        return  view('sandbox', compact('products'));  
    }

and the JS I added

xhr.setRequestHeader('Content-Type', 'application/json');

The ajax response always returns false, but if I put dd($response); outside the if statement, it returns the data just fine, what am I doing wrong?

1 like
chilldsgn's avatar
chilldsgn
OP
Best Answer
Level 16

I fixed it the following way (thanks to some users on stackoverflow.com). Posting here in case anyone else has the same issue. I am not sure if this is the most efficient way, but it works at least.

JS file

const container = document.querySelector('#sandbox-container');
let button = document.getElementById('load-stuff');

button.addEventListener('click', (event) => {
    event.preventDefault();
    const xhr = new XMLHttpRequest();

    let url = button.getAttribute('href');
    let splitUrl = url.split('?'); // split url into two
    let pageNum = button.getAttribute('data-page-number') || 0;
    let newUrl;

    xhr.open('GET', url, true);
    xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');

    pageNum++;
    newUrl = `${splitUrl[0]}?page=${pageNum}`;

    xhr.onload = function() {
        if (xhr.status === 200) {  
            container.insertAdjacentHTML('beforeend', xhr.responseText);
            button.setAttribute('data-page-number', pageNum);
            button.setAttribute('href', newUrl);
        }
        else {
            console.log(`Request failed, this is the response: ${xhr.responseText}`);
        }
    };     
    xhr.send();     
})

Controller:

public function sandbox(Request $request)
    {      
        $products = Product::orderBy('title', 'asc')->paginate(4);

        if($request->ajax()){
        // returns a partial with a basic foreach
            return view('sandbox-more', compact('products'));
        } else {
            return view('sandbox', compact('products'));
        }  
    }

Pagination file (resources>views>vendor>pagination>default.blade.php)

@if ($paginator->hasPages())  
    {{-- Next Page Link --}}
    @if ($paginator->hasMorePages())    
        <a href="{{ $paginator->nextPageUrl() }}" rel="next" class="button bright-turquoise-bg" id="load-stuff" data-page-number="2">Load more</a>
    @else
        <span>»</span>
    @endif
@endif
1 like

Please or to participate in this conversation.