naneri
naneri

Reputation: 3971

How can I paginate two Eloquent collections on a single page with Laravel?

I have two collections on a single page which should be both paginated. But pagination generates the same Parameter for both (?page=X).

How can I solve that kind of an issue?

Upvotes: 3

Views: 1242

Answers (2)

Thomas Kim
Thomas Kim

Reputation: 15921

There is a way to "automatically" set the page name (in a sense), which I'll get to in a bit.

First, if we go over the paginate method, you'll see that it accepts a pageName argument as its 3rd parameter:

public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null)

Lets say you have a User and Post model. You can then do something like this in your controller:

$users = User::paginate(10, ['*'], 'users');
$posts = Post::paginate(10, ['*'], 'posts');
return view('example', compact('users', 'posts'));

It works like your normal pagination except the second argument specifies the columns you want to select and the third argument specifies the page name.

In your view, when you render your pagination links, you might run into a problem when you do this:

{!! $users->render() !!}
{!! $posts->render() !!}

While the pagination links will be rendered, when you click on a link to a posts page, the users query string parameter is gone. Therefore, the users are back to page one and vice versa.

To fix this, you can use the appends method to keep the query parameters for both models:

{!! $users->appends(['posts' => Request::query('posts')])->render() !!}
{!! $posts->appends(['users' => Request::query('users')])->render() !!}

All this works, but it's a bit ugly so how can we clean this up? You can create your own method to "automate" this process. In your model, you can add your own paginate method:

// Name it whatever you want, but I called it superPaginate lol
protected function superPaginate($perPage)
{
    return $this->newQuery()->paginate(10, ['*'], $this->getTable());
}

This will automatically set the pagination name to the model's table name. So for the User model, the page name will be "users". For the Post model, the page name will be "posts".

There's still the problem with rendering links. You don't want to call appends all the time and specify the query parameters. To fix that, we can improve the superPaginate method into this:

protected function superPaginate($perPage, $columns = ['*'], $page = null)
{
    $params = \Request::query();
    return $this->newQuery()->paginate(10, $columns, $this->getTable(), $page)->appends($params);
}

Now, all you need to do is Model::superPaginate(10); and $models->render(). Everything should work properly.

Upvotes: 2

Sulthan Allaudeen
Sulthan Allaudeen

Reputation: 11310

You can change the param of either pagination by

Paginator::setPageName('someparam');

Read more about Pagination here In the section Customizing The Paginator URI

Note : You should do this before paginator is done i.e.,

$yourCollection = Model::paginate(10);

Example :

I assume you have two pagination like this

Paginator::setPageName('yourFirstParam');
$firstCollection = FirstModel::paginate(10);

Paginator::setPageName('yourSecondParam');
$secondCollection = SecondModel::paginate(10);

Where you use this to get in your view

Paginator::setPageName('yourFirstParam');
$firstCollection->links();
Paginator::setPageName('yourSecondParam');
$secondCollection->links();

Upvotes: 1

Related Questions