Implementing a table on a resource-view-page

Hey - I think I'm missing something, so maybe just point me in the right direction. Given I got a resource with a relation to another model. Now what I wanna do is something like this on my view-page:
Section::make('myrelation-headline')
->icon('section-icon')
->schema([
Table::make('myrelation')
->columns([
TextColumn::make('myrelation.property1')
->label('p1-label'),
TextColumn::make('myrelation.property2')
->label('p2-label')
])
])
Section::make('myrelation-headline')
->icon('section-icon')
->schema([
Table::make('myrelation')
->columns([
TextColumn::make('myrelation.property1')
->label('p1-label'),
TextColumn::make('myrelation.property2')
->label('p2-label')
])
])
But Section->schemaexpects type Filament\Forms\Components\Component - so I tried creating my own component via php artisan make:component MyComponent and following the table-builder-docs, but filament seem to not like this aswell, since it's throwing Argument #1 ($component) must be of type Filament\Forms\Components\Component, App\View\Components\MyComponent given. Hopefully I'm missing an easy way here, since I just want a simple table for my relation and creating a new component (even if it works) would just add aditional load to the database, since I already got my relation already loaded through the view-page.
53 Replies
toeknee
toeknee2y ago
Why not use the Relationship Manager for this?
Husky110
Husky110OP2y ago
Might be an idea, but how do I get it into the Section->schema()-function on my view page?
toeknee
toeknee2y ago
So this will allow you to add it to the Resource which is what you are trying to do. It will automatically add it to the footer and if you define more than 1, it will create a tab effect to tab between them
Husky110
Husky110OP2y ago
Ah okay, but that approach is completely out of the question here. My Viewpage is basically a Template which I wanna use for multiple purposes and "just adding to the footer" won't work here. Plus - there will be other components on the footer aswell, so I need a more generalized approach.
toeknee
toeknee2y ago
You asked how to add it to the view page of the resouce. This is how you do that So you have a custom app outside of the resource
Husky110
Husky110OP2y ago
inside the ->schema-function on said view-page... 😉 I was hoping that there is something along the lines of Grid::make -> but with Tables.
toeknee
toeknee2y ago
You cannot add a table to the schema, you could render another component inside it, so a bespoke livewire component with tables added, then just render that livewire component.
Husky110
Husky110OP2y ago
But that gives me the error which I stated above. So I guess that my call to my custom-component might be wrong?
toeknee
toeknee2y ago
You're schema above is not rendering a custom livewire component as far as I can see You have a custom field for Tables but that's all
Husky110
Husky110OP2y ago
I tried my custom-component like this:
Section::make('myheader')
->icon('myicon')
->schema([
new CustomComponent($this->record->id)
])
Section::make('myheader')
->icon('myicon')
->schema([
new CustomComponent($this->record->id)
])
But that resulted in 'Argument #1 ($component) must be of type Filament\Forms\Components\Component, App\View\Components\MyComponent given' -> so maybe my call is wrong here? I don't get what you are trying to tell me with this - sorry. 🙂 But like I said - maybe my custom-component call is wrong? Sorry if I seem a bit dumb - I'm new to the whole Livewire + Filament world. 🙂 I'm used to jQuery and plain old views... 😄
toeknee
toeknee2y ago
The way I would do it is just build a livewire component and implement tables as normal. php artisan make:livewire CustomTables Then use the view field wihtin forms to render that component i.e. livewire.CustomTables You can pass the id within viewData on the view field to fetch the records. If I understand what you are trying to do correctly.
Husky110
Husky110OP2y ago
So my call would actually have to look like this?
Section::make('myheader')
->icon('myicon')
->schema([
View::make('livewire.CustomComponent')->viewData(['id_in_the_constructor' => $this->record->id])
])
Section::make('myheader')
->icon('myicon')
->schema([
View::make('livewire.CustomComponent')->viewData(['id_in_the_constructor' => $this->record->id])
])
I tried that, but then I get Property [$table] not found on component even tho it implements HasTable and uses InteractsWithTable...
toeknee
toeknee2y ago
You need to read the docs on how to add the table to a livewire component 😉
Husky110
Husky110OP2y ago
Hahahaha - I did and that gives me the "property $table not found"-error... 😄 I am genunely wondering if I am too stupid or if i'm missing something... Okay - I will try to retrace my steps here... I think I made an error somewhere.
toeknee
toeknee2y ago
So when that error occurs it means that the livewire component is not setup for tables and tables has now been implemented on the table class. Can you provide your custom component file
Husky110
Husky110OP2y ago
I'm on it - but I have to redact it, since it's a commercial-project. Gimme a minute. 🙂 1.) php artisan make:component MyComponent 2.) adding {{ $this->table }} to the view. 3.) Docs: "Implement the HasTable interface and use the InteractsWithTable trait" -> ✅ 4.) Add relationmarker to constructor for query -> ✅ 5.) Set query and one colum to test. -> ✅ Now my file looks like this:
<?php

namespace App\View\Components;

use Closure;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Concerns\InteractsWithTable;
use Filament\Tables\Contracts\HasTable;
use Illuminate\Contracts\View\View;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\View\Component;

class MyComponent extends Component implements HasTable
{
use InteractsWithTable;

public int $relationID;
/**
* Create a new component instance.
*/
public function __construct( int $relationID)
{
$this->relationID = $relationID;
}

/**
* Get the view / contents that represent the component.
*/
public function render(): View|Closure|string
{
return view('components.my-custom-components.relationship-stuff.thisone');
}

protected function getTableQuery(): Builder
{
return RelationShipModel::where('parent_id', $this->relationID);
}

protected function getTableColumns(): array
{
return [
TextColumn::make('property_one')
->label('header-one')
];
}
}
<?php

namespace App\View\Components;

use Closure;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Concerns\InteractsWithTable;
use Filament\Tables\Contracts\HasTable;
use Illuminate\Contracts\View\View;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\View\Component;

class MyComponent extends Component implements HasTable
{
use InteractsWithTable;

public int $relationID;
/**
* Create a new component instance.
*/
public function __construct( int $relationID)
{
$this->relationID = $relationID;
}

/**
* Get the view / contents that represent the component.
*/
public function render(): View|Closure|string
{
return view('components.my-custom-components.relationship-stuff.thisone');
}

protected function getTableQuery(): Builder
{
return RelationShipModel::where('parent_id', $this->relationID);
}

protected function getTableColumns(): array
{
return [
TextColumn::make('property_one')
->label('header-one')
];
}
}
and the Secion-code should look like this then: Section::make('myheader') ->icon('myicon') ->schema([ View::make('components.my-custom-components.relationship-stuff.thisone')->viewData(['relationID' => $this->record->id]) ]) those were my steps so far...
awcodes
awcodes2y ago
You’re not using a livewire component. Using make:view creates a laravel component. They are different things.
Husky110
Husky110OP2y ago
No - I used php artisan make:component MyComponent -> should that not create a Livewire-Component? Is Laravel (10) dumb here? 😄
awcodes
awcodes2y ago
That is wrong. You need make:livewire to create a livewire component. Laravel component !== Livewire component.
toeknee
toeknee2y ago
Like I posted above 🤣 it’s not your day @husky110 😜
Husky110
Husky110OP2y ago
I love you too man. ❤️ 🤣 Okay - I tried using a livewire-component but i'm still getting "Property [$table] not found on component : [app.filament.resources.shippingmanagement.deliveries-resource.pages.view-deliveries]" -> which is actually the page and not the component-view? The flying f? @awcodes - We need a dumbed down Table-Component simillar to "Grid::make" - like Table::make for morons like me... 😄
awcodes
awcodes2y ago
Well, tables inside of forms isn’t a common use case. There is a table widget though.
Husky110
Husky110OP2y ago
Actually I'm on a view-page (like /show) and not a form...
awcodes
awcodes2y ago
The view page is just a disabled form.
Husky110
Husky110OP2y ago
Under the hood - possible. But here I see a pretty heavy usecase, since it's about displaying details. 🙂
awcodes
awcodes2y ago
And tables themselves dont work inside a form because they use forms themselves for the filters and in html you can’t nest forms.
Husky110
Husky110OP2y ago
That's what I meant with "dumbed down" -> there are no filters! Just show me the freaking relation-details and that's it. 😄
awcodes
awcodes2y ago
Thats why we have the table widget. You just won’t be able to add it to a section inside the form schema. That’s exactly what relation managers do. You still can’t put them in a form schema though.
Husky110
Husky110OP2y ago
And that's my problem with that... 😄 I have to develop that 💩 myself - right? 😄
awcodes
awcodes2y ago
You could still use a custom view with a normal table. Or you can make a custom page then layout any way you need. You just can’t use the tables package inside a form. That’s a limitation of html since the tabes package uses forms for certain aspects of the table.
Husky110
Husky110OP2y ago
Hmm - maybe an idea for V3 or a plugin... Like some sort of "easy" table that just shows records, but has none of the comfort-features. Cause the output of the table-package is great and does not use traditional tables. Would be realy great to have that easily accessible.
awcodes
awcodes2y ago
V3 will have InfoLists. Not really a table but a more controlled way to display readonly data.
Husky110
Husky110OP2y ago
What we are talking here about is listing the positions on a deliveryslip (I can say that much) and there something along the lines of Table::make('relationname')->columns([TextColumn::make('relation_p1'), TextColumn::make('relation_p2')]) would be really cool.
awcodes
awcodes2y ago
GitHub
filament/packages/infolists/docs/02-getting-started.md at 3.x · fil...
Admin panel, form builder and table builder for Laravel. Built with the TALL stack. Designed for humans. - filament/packages/infolists/docs/02-getting-started.md at 3.x · filamentphp/filament
Husky110
Husky110OP2y ago
Thanks. Right now I'm fearing that V3 will have to include a rewrite of anything I've done with V2 so far, which is not in my ballpark for the next 3-4 months at least, since I'm developing my app alone.
awcodes
awcodes2y ago
It will include an upgrade script that should limit what you’ll need to rewrite.
Husky110
Husky110OP2y ago
Yep - still a month away tho and I will wait a bit longer, just to get the first common bugs out. 😉 Okay - back to my table... So I will have to build it myself somehow - got it.
awcodes
awcodes2y ago
Obviously, custom components and things like that are outside the scope of that script.
Husky110
Husky110OP2y ago
I reckoned. 🙂
awcodes
awcodes2y ago
There’s also #awcodes-table-repeater which might get you what you’re after. Might have to massage the data a little though. It’s an extension of the repeater formatted to render as a table.
Husky110
Husky110OP2y ago
Hmm - I was think about this one aswell... But for now I think I will just make a custom view and get done with it. So for now - anyone reading this: Getting a filament-style-table into a page is not really directly possible at the moment.
Patrick Boivin
Wellll, it is possible, just not exactly simple 🙂 Here's a table in a form :
Patrick Boivin
I've used tables like this in many places and the key is really what toeknee and awcodes have said above: to rely on custom livewire components to wrap the table and to know the implications of nested form tags. Either you avoid the outer form tag (you can use a full filament form without a wrapping form tag) or you make sure not to rely on the inner form's behavior (because the browser will extract it out of the parent form element)
toeknee
toeknee2y ago
Great
Husky110
Husky110OP2y ago
Can you please provide some code for this? 🙂
Patrick Boivin
I'm planning on writing a short article on it in the Tricks section of the website. In the meantime, maybe I can help you from where you are now. What solution did you land on in the end for your use-case?
Husky110
Husky110OP2y ago
you'll love this 😅
Patrick Boivin
Just to recap what I have in the short video ☝️ - Starting on a regular Filament Edit page - Added a form component as a wrapper for a custom Livewire component - Added the Livewire component, implementing the HasTable interface - Modified the table Blade template to remove the nested form elements (not needed for my use-case)
Husky110
Husky110OP2y ago
<table class="table-auto w-full">
<thead>
<tr>
<th>{{ m__('translate1') }}</th>
<th>{{ m__('translate2') }}</th>
<th>{{ m__('translate3') }}</th>
</tr>
</thead>
<tbody>
@foreach($data as $datapoint)
<tr>
<td class="text-center">{{ (new \Illuminate\Support\Carbon($datapoint->created_at))->format('d.m.Y - H:i:s') }}</td>
<td class="text-center" x-data x-tooltip.raw="{{ m__('translate4.'.$datapoint->something->key.'.explain') }}">{{ m__('translate5.'.$datapoint->something->key.'.short') }}</td>
<td class="text-center"> {{ $datapoint->changed_by == 0 ? 'MySoftware' : \App\Models\User::findOrFail($datapoint->changed_by)->name}}</td>
</tr>
@endforeach
</tbody>
</table>
<table class="table-auto w-full">
<thead>
<tr>
<th>{{ m__('translate1') }}</th>
<th>{{ m__('translate2') }}</th>
<th>{{ m__('translate3') }}</th>
</tr>
</thead>
<tbody>
@foreach($data as $datapoint)
<tr>
<td class="text-center">{{ (new \Illuminate\Support\Carbon($datapoint->created_at))->format('d.m.Y - H:i:s') }}</td>
<td class="text-center" x-data x-tooltip.raw="{{ m__('translate4.'.$datapoint->something->key.'.explain') }}">{{ m__('translate5.'.$datapoint->something->key.'.short') }}</td>
<td class="text-center"> {{ $datapoint->changed_by == 0 ? 'MySoftware' : \App\Models\User::findOrFail($datapoint->changed_by)->name}}</td>
</tr>
@endforeach
</tbody>
</table>
I call it "the crappy livewire-/filament-noob-approach that get's the job done. 😄 View::make('myshittyapproach')->viewData(['data' => $lol]);
Patrick Boivin
If it's any encouragement for you, I'm also doing this in another part of my app (custom <table> markup reusing the filament CSS classes)
Husky110
Husky110OP2y ago
hmmm - seeing my m again - I really should make a package out of it... to anyone seeing this -> m is my memcached-replacement for the __ function ^^
Want results from more Discord servers?
Add your server