DEV Community

Julia Lange for visuellverstehen

Posted on

How to add pagination to your custom relationship fieldtype in Statamic

Usually when building a custom relationship fieldtype you want to work with data from somewhere else than Statamic.

In this example we extended the relationship fieldtype in order to provide a list of imported tags. Thanks to the Statamic docs, this is pretty easy.

class Tags extends Relationship
{
    protected array | string $tags;

    // Fetch tags from api. 
    // Using a facade makes it nice to read and easier to test.
    public function __construct()
    {
        $this->tags = Api::tags();
    }


    // Define columns.
    protected function getColumns()
    {
        return [
            Column::make('title'),
        ];
    }

    // Take search requests into account. 
    // Just comparing strings. Nothing fancy.
    public function getIndexItems($request)
    {
        return collect($this->tags)
          ->filter(function ($tag) use ($request) {
            if (! $request->search) {
                return true;
            }

            return Str::contains($tag['title'], $request->search);
        });
    }
}
Enter fullscreen mode Exit fullscreen mode

In many cases this would already be it. But what if you have a huge amount of tags or items that need to be loaded into Statamics selector stack?
I found that loading about 16000 tags at once into the selector stack would either cause unbearable loading times or even make the browser freeze.

This issue could be solved by enabling pagination. But unfortunately the relationship fieldtype does not automatically enable pagination when loading a specific number of items.

In order to do so and show pagination at the bottom of the selector stack you need to return an instance of the \Statamic\Extensions\Pagination\LengthAwarePaginator instead of a collection in the getIndexItems method.

This could be done like this:

public function getIndexItems($request)
    {
        $tags = collect($this->tags)->filter(function ($tag) use ($request) {
            if (! $request->search) {
                return true;
            }

            return Str::contains($tag['title'], $request->search);
        });

        return $this->paginate($tags);
    }


    protected function paginate($tags): LengthAwarePaginator
    {
        $currentPage = Paginator::resolveCurrentPage();
        $perPage = 50;
        $total = $tags->count();
        $result = $total ? $tags->forPage($currentPage, $perPage) : collect();

        return new LengthAwarePaginator($result, $total, $perPage, $currentPage, []);
    }
Enter fullscreen mode Exit fullscreen mode

Curios about the LengthAwarePaginator? Read more in the Laravel Docs

Et voilà - a custom relationship fieldtype with added pagination:

A custom relationship fieldtype with added pagination in Statamic

Top comments (0)