Ari
Ari

Reputation: 418

Combining laravel pagination with live search using ajax

I have a list of projects displayed in a table which has a pagination at the bottom by using laravel's paginatation.

$projects = projects::where('active', '=', 1)->orderBy('id', 'desc')->paginate(15);
return view('index', compact('projects'));

I also have a live search to filter the projects by name, using ajax.

public function search(Request $request){
        if($request->ajax()){
            $query = $request->get('query');
            if($query != ''){
                $data = DB::table('projects')
                 ->where('active', '=', 1)
                 ->whereNull('deleted_at')
                 ->where('name', 'like', '%'.$query.'%')
                 ->get();

            }else{
                $data = DB::table('projects')->where('active', '=', 1)->whereNull('deleted_at')->orderBy('id', 'desc')->get();
            }

        }
        return response($data->jsonSerialize(), Response::HTTP_OK);
    }

Js:

searchProjects = function(query){
        $.ajax({
            url: "/projects/search",
            type: "POST",
            data: {
                query: query,
            },
            success: function (response){
                displayData(response);
            }
        })
    },

So first I load the projects via server side and then if I do a search, the data gets replaced with the result via ajax.

The problem I'm facing is that whenever I do a search, the paginations doesn't update. Let's say the search displays 5 results, I want the pagination to go from 1-2 to 1-1 or even just disappear (if that makes sense) if there are less than 15 results (for instance).

Does anyone have any idea how I would combine both a live search and a pagination that work together on laravel?

Upvotes: 0

Views: 5930

Answers (2)

Bart Seresia
Bart Seresia

Reputation: 36

I believe your problem is you want to combine both PHP generated HTML with JS generated HTML.

The paginate part will generate a specific HTML, if you want to update your data without a full reload of the page (via the Ajax call) you need to regenerate the HTML. You can do this by creating a JS that builds your HTML. However this would mean you have 2 places to maintain your HTML.

I would propose to update your code to (instead of the JSON data) return a newly generated HTML part, and inject this new HTML in your page.

Also be sure to update your search function to make full use of you model instead of using the DB::table.

Hope this response is a bit clear.

Upvotes: 2

Adis Azhar
Adis Azhar

Reputation: 1022

Let's say you have a jobs/index.blade.php file. This will act as the base file for your jobs. It will list all the jobs available:

<div class="container">
        <div class="row">
            <div class="col-sm-9">

                @if (count($jobs) > 0)
                    <section class="jobs">
                        @include('jobs.load')
                    </section>
                @endif

            </div>

            <div class="col-sm-3">
            </div>
        </div>
    </div>

<script>
    $(function() {
        $('body').on('click', '.pagination a', function(e) {
            e.preventDefault();

            $('#load a').css('color', '#dfecf6');
            $('#load').append('<img style="position: absolute; left: 0; top: 0; z-index: 100000;" src="/images/loading.gif" />');

            var url = $(this).attr('href');
            getJobs(url);
            window.history.pushState("", "", url);
        });

        function getJobs(url) {
            $.ajax({
                url : url,
                success: function(data) {
                    $('.jobs').html(data);
                },
                error: function(err) {
                    alert("jobs cannot be loaded");
                    console.log(err);
                }
            });
        }
    });
</script>

This will be the file component, jobs/load.blade.php that will be requested on the ajax:

<div id="load" style="position: relative;">
@foreach($articles as $article)
    <div>
        <h3>
            <a href="{{ action('ArticleController@show', [$article->id]) }}">{{$article->title }}</a>
        </h3>
    </div>
@endforeach
</div>
{{ $articles->links() }}

Now to open the page, you will need a controller function, it is self documented:

   public function index(Request $request)
    {
        // get jobs and limit to 5 data
        $jobs = Jobs::paginate(5);

        // this condition will be executed on the ajax request
        // that is everytime you click on prev/ next
        // it will be handled by jquery's .html() function
        if ($request->ajax()) {
            return view('jobs.load', ['jobs' => $jobs])->render();  
        }

        // on traditional HTTP request, it will load the base page
        return view('jobs.index', compact('jobs'));
    } 

Reference:

https://laraget.com/blog/how-to-create-an-ajax-pagination-using-laravel

Upvotes: 2

Related Questions