Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

jlcain3's avatar

Inertia Datatable

Hello All

I've just started working with inertia and vue.js after working with livewire and alpine over the last couple of years and I have a question regarding re-usable components that I can't quite get my head around.

The task: Build a re-usable datatable component to show a paginated view of companies that is sortable and filterable via a search input.

In livewire I would have created the component and dropped the component onto another view

<livewire:company.datatable />

The livewire view would of course hold the mark up for the table and then with the class I would write the query to get the companies, something like...

...

public function render()
    {
        return view('livewire.company.datatable', [
            'companies' => $this->getFilteredCompanies(),
        ]);
    }

    public function getFilteredCompanies(): LengthAwarePaginator
    {
        $query = Company::orderBy($this->sortField, $this->sortDirection)         
            ->withCount('users');

        if (!is_empty_string($this->search)) {
            $query->where(function (Builder $query) {
                $query->where('id', $this->search)
                    ->orWhere('name', 'like', '%'.$this->search.'%')
                    ->orWhere('client_id', 'like', '%'.$this->search.'%');                    
            });
        }

        return $query->paginate(8);
    }

Simple and re-usable by just dropping the component on any page. Could probably move the query for company into a service or something if it needed to be used somewhere else etc.

Now in inertia/vue.js:

I have a CompanyController with an index method that returns and Inertia response

class CompanyController extends Controller
{   
    public function index(Request $request, CompanyService $service)
    {
        return Inertia::render('admin/Company/Index', $service->index());
    }

The paginator is located in the CompanyService class

class CompanyService
{
    public function __construct(Request $request)
    {
        $this->request = $request;
    }

    public function index(): array
    {
        $sortField = $this->request->input('sort', 'id');
        $sortDirection = $this->request->input('direction', 'desc');
        $search = $this->request->input('search', null);

        $query = Company::orderBy($sortField, $sortDirection)
            ->with('users', 'domains')
            ->withCount('users');

        if (isset($search)) {
            $query->where(function (Builder $query) use ($search) {
                return $query->where('name', 'like', '%'.$search.'%')
                    ->orWhere('id', $search)
                    ->orWhereHas('domains', function (Builder $query) use ($search) {
                        return $query->where('domain', 'like', '%'.$search.'%');
                    });
            });
        }

        $paginator = $query->paginate(10)
            ->through(function ($company) {
                return [
                    'id' => $company->id,
                    'name' => $company->name,
                    'domains' => $company->domains->map(function ($domain) {
                        return [
                            'key' => $domain->id,
                            'domain' => $domain->domain,
                        ];
                    }),
                    'usersCount' => $company->users_count,
                    'users' => $company->users->map(function ($user) {
                        return [
                            'key' => $user->id,
                            'name' => $user->name,
                            'email' => $user->email,
                        ];
                    }),
                ];
            });

        return [
            'paginator' => $paginator,
            'meta' => [
                'sort' => $sortField,
                'direction' => $sortDirection,
                'search' => $search,
            ],
        ];
    }
}

And in the Index.vue I have a <CompanyDatatable /> component that I pass the paginator to as props.

Anyways, what feels weird is that I feel like I should not be passing the paginator through in the controller method and then as props, but maybe doing some additional fetch or axios request from within the <CompanyDatatable /> component to another endpoint that just serves that component?

Maybe it is just a paradigm shift on my part but it doesn't "feel" right.

Any insight/advice would be appreciated.

Thanks Josh

0 likes
2 replies
undeportedmexican's avatar
Level 15

I believe it's precisely what you said in the end, a bit of paradigm shift.

By using Inertia in the 'intended' way, which is leveraging the full backend power of laravel, and the flexibility that Vue offers. In that sense, you would definitely need to pass the prop down if you want to do it using inertia tools.

Having said that, absolutely nothing prevents you from doing what you mentioned, which is using an axios call integrated within the component to de-couple it from the parent controller.

Inertia is meant to glue your laravel and vue apps together, but in the end it's still a VueJS app, and you can leverage any of it's functionalities without messing the Inertia stack.

1 like

Please or to participate in this conversation.