jonassiewertsen / statamic-livewire

A Laravel Livewire integration for Statamics antlers engine
85 stars 15 forks source link

How to use pagination? #4

Closed aerni closed 3 years ago

aerni commented 3 years ago

Is there a way to use pagination like documented here? In Blade you would use {{ $posts->links() }} to render the pagination view? I couldn't figure out a way to do this in Antlers.

jonassiewertsen commented 3 years ago

Good find @aerni and a good question.

I haven't used pagination in any Antlers context yet, but this might be interesting 😀

Are you using a default Statamic collection or are you fetching information via Eloquent?

aerni commented 3 years ago

I'm using Statamic's QueryBuilder:

Entry::query()
    ->where('collection', $this->collection)
    ->paginate($this->perPage);

This returns an instance of Illuminate\Pagination\LengthAwarePaginator.

If you use the toArray method after paginate, it returns an array that also includes an array of links.

aerni commented 3 years ago

Alright, I did some diving. It's actually quite simple to solve without any further ado.

The entry query returns an instance of Illuminate\Pagination\LengthAwarePaginator. This class exposes an items and render method. The items method can be used to get the paginated items. And the render method can be used to render the pagination view.

In your Livewire component class:

protected function entries()
{
    return Entry::query()
        ->where('collection', 'articles')
        ->paginate(3);
}

public function render()
{
    return view('livewire.blog-entries', [
        'entries' => $this->entries()->items(),
        'links' => $this->entries()->render()
    ]);
}

In your Livewire component view:

{{ entries }}
    ...
{{ /entries }}

{{ links }}

We could make this even simpler for users by providing a trait with a simple function:

public function withPagination($key, $paginator)
{
    return [
        $key => $paginator->items(),
        'links' => $paginator->render(),
    ];
}

And then in the Livewire component class:

protected function entries()
{
    $entries = Entry::query()
        ->where('collection', 'articles')
        ->paginate(3);

    return $this->withPagination('entries', $entries);
}

public function render()
{
    return view('livewire.blog-entries', $this->entries());
}

What do you think?

jonassiewertsen commented 3 years ago

Thanks for the digging @aerni !

I like the idea of providing a trait a lot. This solution does feel very clean to me.

jonassiewertsen commented 3 years ago

Do you like to create a PR or should I write it up @aerni ?

aerni commented 3 years ago

Cool! I'm happy to PR this. Do you think we should create a WithPagination trait in the Jonassiewertsen\Livewire namespace that uses the Livewire provided WithPagination trait? This way the user only has to import one trait.

jonassiewertsen commented 3 years ago

That's how I would do it.

jonassiewertsen commented 3 years ago

Closed via https://github.com/jonassiewertsen/statamic-livewire/pull/6

YahzeeSkellington commented 3 years ago

New to Statamic and I just found this package. I cannot get pagination to work. I implemented everything as the documentations says but I can only get the first page of results. Whenever a click any button for the next set of results I get a lightbox with my 404 page.

The console shows this:

index.js:32 POST http://example.test/livewire/message/show-illustrations 404 (Not Found)

My component:

namespace App\Http\Livewire;

use Jonassiewertsen\Livewire\WithPagination;
use Livewire\Component;
use Statamic\Facades\Entry;

class ShowIllustrations extends Component
{
    use WithPagination;

    protected function entries()
    {
        $entries = Entry::query()
            ->where('collection', 'illustrations')
            ->paginate(3);

        return $this->withPagination('entries', $entries);
    }

    public function render()
    {
        return view('livewire.show-illustrations', $this->entries());
    }
}

My component view


<div>
    <ul>
        {{ entries }}
            <li>{{ title }}</li>
        {{ /entries }}
    </ul>

    {{ links }}
</div>

...

What am I missing here?