RileyGWeb's avatar

Paginating an existing table with Livewire

I have a plain HTML table being rendered with the results of an Eloquent query.

// controller
$this->tableData['headers'] = $tableHeaders;
$this->tableData['rows'] = $query->get(); 

(classes, attributes and other removed for readability)

<!-- view -->
<table>
    <thead>
        <tr>
            @foreach( $tableData['headers'] as $val )
                <th>{{ $val }}</th>   
            @endforeach
        </tr>
    </thead>
    <tbody>
        @foreach( $tableData['rows'] as $row )
            <tr>
                @foreach ( $row as $key => $val )
                    <td>{{ $val }}</td>
                @endforeach
            </tr>
        @endforeach
    </tbody>
</table>

When I read the docs on Livewire's pagination, it seems to want paginate() called on a model of some sort.

// from the docs
public function render()
    {
        return view('livewire.show-posts', [
            'posts' => Post::paginate(10),
        ]);
    }

I don't really understand; if possible, how can I get this pagination feature to meet me where I'm at? If it's not possible, what would be best for me to do otherwise?

(P.S. I'm aware of the Livewire Datatables package - great package, but does not work for my specific needs due to reasons unrelated to this post)

0 likes
5 replies
Sinnbeck's avatar

Why does it need to go inside the $tableData array? I don't think I understand the reason?

RileyGWeb's avatar

@Sinnbeck I suppose it doesn't have to, that's just what I have right now and I'm not sure what my next step should be.

I'm more asking about where exactly I put paginate() with my current setup.

Sinnbeck's avatar

@Coaster132 if I understand correctly, just pass down pagination like you show and do this

@foreach( $tableData['rows'] as $row ) //before 
@foreach( $posts as $row ) //after
RileyGWeb's avatar

@Sinnbeck That 3rd block of code is from the docs, not from my project. To replicate in my code...

public function render()
{
    return view('livewire.dimensions-filter', [
        'rows' => ????
    ]);
}

What do I replace ???? with? I do not have a model that I can call ::Paginate() on. The docs do not provide an alternate way to pass pagination down.

Is there a way to perhaps create a pagination instance and pass my data into it manually? Maybe something like this Laracasts post, but I get lost at the $items = $collection->forPage($this->page, $perPage); line.

RileyGWeb's avatar

I thought I would share my solution in case anyone else stumbles across this.

public function render () {
    $perPage = 15;

    $rawCollection = $this->tableData['rows']; // Raw results of $query->get()
    $fixedCollection = new Collection();
    if (gettype($rawCollection) == "array") {
        foreach($rawCollection as $key => $val) {
            $fixedCollection->put($key, $val);
        }
    } else {
        $fixedCollection = $rawCollection;
    }

    $items = $fixedCollection->forPage($this->page, $perPage);
    $paginator = new LengthAwarePaginator($items, $fixedCollection->count(), $perPage, $this->page);

    return view('livewire.dimensions-filter', [
        'rows' => $paginator,
    ]);
}
<!-- table made with... -->
@foreach( $rows as $row )

<!-- table navigation -->
<div class="mt-4">
    {{ $rows->links() }}
</div>

The short answer is that Paginate just wants a collection, and calling it on a model (Posts::paginate()) is an easy way to get that collection. But if you don't have a model to call it on, you can do $someProp = new Collection() and go from there, like I did above.

The raw/fixedCollection strangeness was because although the page loaded fine, when I went to click Next Page, my $collection property would turn into an array from a collection, and it needs to be a collection. That little block of code turns it into a collection.

Anyway, that's how paginated an existing HTML table without having a model to call paginate() on like the docs show. Hopefully this helps someone.

Please or to participate in this conversation.