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