ejntaylor
ejntaylor

Reputation: 2101

Paginate results with Vue.Js / Inertia.js and Laravel

I'm trying to paginate data from Laravel in Vue.Js. I'm using Inertia.js as well.

In my Laravel Controller I have:

    $data['participants'] = User::with('groups')->select('id', 'name')->paginate(2);
    return inertia('Dashboard/Participants', $data);

This outputs my two users in a row well in Vue. I am also expecting the links object to use for pagination. I don't see this in my Vue props.

If I inspect my Vue props I have the following object:

participants:Object
 current_page:1
 data:Array[2]
 first_page_url:"http://localhost:3000/dashboard/participants?page=1"
 from:1
 last_page:51
 last_page_url:"http://localhost:3000/dashboard/participants?page=51"
 next_page_url:"http://localhost:3000/dashboard/participants?page=2"
 path:"http://localhost:3000/dashboard/participants"
 per_page:2
 prev_page_url:null
 to:2
 total:101

If I:

dd($data['participants']->links());

in the controller I can see:

Illuminate\View\View {#316 ▼
  #factory: Illuminate\View\Factory {#310 ▶}
  #engine: Facade\Ignition\Views\Engines\CompilerEngine {#328 ▶}
  #view: "pagination::bootstrap-4"
  #data: array:2 [▶]
  #path: "/Users/ejntaylor/Documents/Laravel/motional/vendor/laravel/framework/src/Illuminate/Pagination/resources/views/bootstrap-4.blade.php"
}

I have been looking at PingCRM for inspiration but without luck - I've referenced in the link. Help appreciated.

Upvotes: 2

Views: 9766

Answers (2)

svnwa
svnwa

Reputation: 31

I had a similar problem and noticed the basic links() wouldn't work with Inertia and Vue so i made a simple Vue component where I use the Paginator Object I get from the Inertia render method and it works very well for me without the ServiceProvider workaround.

I can just use

public function index()
{
    return Inertia::render('MyUserList',[
        'paginator' => User::paginate(10)
    ]);
}

as I normally would. Then i bind the paginator Object to my Vue Component so I can leverage it to create a basic Paginator component. This way I can use and reuse the <Paginator :paginator="paginator" /> anywhere I want.

<template>
    <Paginator :paginator="paginator" />
</template>

<script>
import Paginator from "@/Components/Paginator";
export default {
    props: {
            paginator: Object
        },
}
</script>

I also created a package so you can pull it in via composer if you want. See https://github.com/svnwa/InertiaVuePaginator for more Info and the "Components" folder for the paginator component i created. I hope it helps others in the future :)

Upvotes: 3

ejntaylor
ejntaylor

Reputation: 2101

It would seem the default Laravel pagination does not work with Inertia.JS so you must head to your AppServiceProvider.php file and add the following to get pagination to work.

This is taken from PingCRM

 protected function registerLengthAwarePaginator()
{
    $this->app->bind(LengthAwarePaginator::class, function ($app, $values) {
        return new class(...array_values($values)) extends LengthAwarePaginator {
            public function only(...$attributes)
            {
                return $this->transform(function ($item) use ($attributes) {
                    return $item->only($attributes);
                });
            }

            public function transform($callback)
            {
                $this->items->transform($callback);

                return $this;
            }

            public function toArray()
            {
                return [
                    'data' => $this->items->toArray(),
                    'links' => $this->links(),
                ];
            }

            public function links($view = null, $data = [])
            {
                $this->appends(Request::all());

                $window = UrlWindow::make($this);

                $elements = array_filter([
                    $window['first'],
                    is_array($window['slider']) ? '...' : null,
                    $window['slider'],
                    is_array($window['last']) ? '...' : null,
                    $window['last'],
                ]);

                return Collection::make($elements)->flatMap(function ($item) {
                    if (is_array($item)) {
                        return Collection::make($item)->map(function ($url, $page) {
                            return [
                                'url' => $url,
                                'label' => $page,
                                'active' => $this->currentPage() === $page,
                            ];
                        });
                    } else {
                        return [
                            [
                                'url' => null,
                                'label' => '...',
                                'active' => false,
                            ],
                        ];
                    }
                })->prepend([
                    'url' => $this->previousPageUrl(),
                    'label' => 'Previous',
                    'active' => false,
                ])->push([
                    'url' => $this->nextPageUrl(),
                    'label' => 'Next',
                    'active' => false,
                ]);
            }
        };
    });
}

Upvotes: 3

Related Questions