Skip to main content
Firstlight / NativePHP

Firstlight / Docs

Native controls, Laravel validate/submit/authorize on native screens, and how Firstlight complements NativePHP Mobile UI.

View source
Paginate Firstlight lists

Paginate Firstlight Lists

Firstlight paginates lists in PHP. List already exposes @refresh and @end-reached. The helper accumulates Laravel paginator pages into $this->listItems so Blade can render ordinary List Item rows.

There is no <firstlight:empty> tag and no second scroll-event API.

Declare the screen

Extend FirstlightUI\NativeComponent (or use PaginatesLists):

<?php

namespace App\Native;

use App\Models\Conversation;
use FirstlightUI\NativeComponent;
use FirstlightUI\Pagination\ListPage;

class InboxScreen extends NativeComponent
{
    public function mount(): void
    {
        $this->reload();
    }

    public function reload(): void
    {
        $this->refreshList(
            fn (ListPage $page) => Conversation::query()->latest()->paginate(
                perPage: 20,
                page: $page->page,
            ),
        );
    }

    public function loadMore(): void
    {
        $this->loadMoreList(
            fn (ListPage $page) => Conversation::query()->latest()->paginate(
                perPage: 20,
                page: $page->page,
            ),
        );
    }
}

refreshList() replaces $this->listItems with the first page. loadMoreList() appends the next page. Both return false when a fetch is already running. loadMoreList() also returns false without querying when $this->listHasMore is false.

Pass the paginator's page from ListPage. NativePHP has no HTTP ?page= query string for these events.

Render the rows

@if (count($this->listItems) === 0)
    <firstlight:status-label
        label="No conversations yet"
        tone="neutral"
    />
    <firstlight:callout
        message="Pull to refresh after you add a conversation."
        tone="info"
    />
@endif

<firstlight:list separator @refresh="reload" @end-reached="loadMore">
    @foreach ($this->listItems as $conversation)
        <firstlight:list-item
            :headline="$conversation->title"
            @press="openConversation"
        />
    @endforeach
</firstlight:list>

Keep @end-reached bound even on the last page. Extra events are ignored.

Empty copy is ordinary Blade around List. Compose Status Label, Callout, and Button when you need a retry action.

Cursor pagination

ListPage::$cursor is null on refresh and the previous paginator's next cursor afterward. Pass it through to cursorPaginate():

use Illuminate\Pagination\Cursor;

$this->refreshList(
    fn (ListPage $page) => Conversation::query()->latest()->cursorPaginate(
        perPage: 20,
        cursor: $page->cursor !== null ? Cursor::fromEncoded($page->cursor) : null,
    ),
);

Use the same callable with loadMoreList().

Unexpected exceptions from the query are not converted to Feedback. Screens that extend NativePHP's component directly can opt in with FirstlightUI\Concerns\PaginatesLists.

To delete a row after Confirmation Dialog authorization, see Destroy list items.

Served from firstlightui/nativephp and cached for a fast first read.