Custom field: bind array data
I created a custom field and this custom field renders mutliple Filament Checkboxes:
As you can see I bind the input to the
state
. The problem is that this binds every Checkbox to the state and this results in every checkbox using the same state (so only one true/false value for all checkboxes). How can I bind each checkbox to an array in the state?39 Replies
Add the array key to the x-model?
You mean like this:
<x-filament::input.checkbox x-model="state[0]" />
?
I don't use a custom form or custom livewire component. I use the custom field inside an action form:
I treid it using this:
<x-filament::input.checkbox x-model="{{state[$loop-index]}}" />
But this gives an error:
Any ideas how to use an array in the state?Ah, I am a bit confused because you are mixing Alpine and Blade
You probably should use Alpine for the
for
loop. Not Blade.Could you give me a small example?
I think something like this:
But there are no items in the state. The permissions are not directly database fields of the model. Thats the reason why I build a custom field, because I need a custom ui and a custom handling for how the field data is handled
But I will give it a try using an alpine for loop
You would still return an array with true/false for every permission ID I guess?
Yep
So then it's something like this?
Thats what I already tried (this is still a php foreach Loop?) and leads to the unknown constant error above
No. It's what you tried but with the proper syntax.
Ah right
Alpine-based. You mixed up JS and PHP
Yes I see. The curly braces are after the state variable. I will give it a try and let you know. Thanks!
OK. I tried it but I doesn't work as expected:
1. I get errors in the browser console:
2. I get an empty state after form submit:
[2024-05-07 12:39:24] production.DEBUG: Setting permissions: {"permissions":null}
It's bacause you are using UUID and those are strings not ints. So you need to wrap them inside quotes
Also make sure to always pass an array as the state
I wrapped them in single quotes and the resulting HTML looks fine:
state['9bb7cb42-e662-47ad-a566-d45ca240efed']
But I still get errors in the browser console (now different).
In the code:
<x-filament::input.checkbox x-model="state['{{$permission->id}}']" />
And I don't know how to pass an array as the state. I use the custom field in the action form as stated above and I didn't find a solution to pass a state to that form.
Not sure. I haven't build a more complex field myself. I guess you should be able to define
->default([])
for your field (if on a Create Page). Otherwise the default should already be there. It shouldn't be about the field itself because state is passed from the page.I already had a hard time building a custom field. The docs are a bit limited regarding arrays and the data binding itself. Also it seems like there are a lot of differences in using a custom field in a form. The form itself can be used inside an action, inside a Livewire Component (e.g. custom page) or in my case: A form inside an action inside a RelationManager.
Btw: Setting
->default([])
removes the errors on first opening the form with the custom field but gives errors on submitting the form. The state itself seems to be null, too
[2024-05-07 13:11:04] production.DEBUG: Setting permissions: {"permissions":[]}
Also what is very confusing to me is that a custom field seems to be no Livewire Component on its own and so I am unable to set properties in the custom field class and I am also unable to use
$this
in the custom field view, because $this
references the Livewire Component the field is rendered in (in my case a RelationManager).Also what is very confusing to me is that a custom field seems to be no Livewire Component on its ownYes. If every field was a Livewire component this would be a hell to maintain and probably a performance hell, too 🙈 I know custom fields are more complicated because they don't follow Livewire components.
Currently I am thinking about using a custom page instead. Is it possible to render a set of fields in a form using a foreach in Filament? For example:
I need to render a Checkbox for each permission a project has - but each project can have a different amount of permissions.
Fields are "pretty dumb". You pass in a state that can be modified and passed back.
yes... I think using a complete custom form could help me out
Btw. what you are trying to build looks pretty similar to CheckboxList. Is there a difference?
I was trying to use CheckboxList first but I need a proper styling. I have a bit of a complicated relationship between Users, Projects, Roles and Permissions.
- Users have Roles
- Users have Permissions
- Projects have Users through Roles
- Roles and Permissions can have Polymorphic Relations to other Models (in this case a Project)
- Permissions can belong to a Destination
What I want to achieve:
Manage the Users of a Project. But because Users are not directly related to a Project (only using a hasThrough with Roles) I did not find any built-in way in Filament to manage such a relationship. Instead I need to manage the roles and permissions of a user in the context of a project. That's the point why I thought using a custom field for the permissions could work here.
The CheckboxList would be a good fit. But I want the CheckboxList to look a bit different:
List the checkbox for each project permission per destination. So like:
internal:
[ ] Upload
[ ] Download
external:
[ ] Upload
[ ] Download
and so on.
Also it seems like the CheckboxList itself can not be used in a custom field or view and is not stated in https://filamentphp.com/docs/3.x/support/blade-components/overview
Btw: Thank you so much for your time helping me out!
Currently I am trying the custom page approach but I am not sure how to pass the current ownerRecord as a route parameter, because I can't access it directly using
$this
. Do you have an idea?
->url(fn ($livewire) => $livewire->ownerRecord)
OK. Really nice I forgot that I can nearly use dependency injection anywhere in Filament!
I am still struggling to point to my custom page..
My UserResource:
ProjectResource:
UsersRelationManager:
But I get the error
Route [users.manage-project] not defined.
I thought as soon as a page is listed in a resource I could route to it using a named route..?
The route also exists:
Yeah. That's not what Filament registers. Use Filaments helper method:
Page::getUrl($args)
I thought as soon as a page is listed in a resource I could route to it using a named route..?Compare the names:
users.
and filament.admin.resources....
ah I see
I changed it to:
But this route is not defined?
Route [http://localhost/admin/users/9bb5ab66-7485-4d9e-b806-a9a05abe7f91/projects/9bb7cb42-b9f8-4192-9f6c-14adf7189dbf] not defined.
I am confused - exactly that route is listed in artisan route:list
?
You passed an URL to the
route()
function. You don't need the route function anymoreYou are right. I changed it:
But still getting a 404 error after clicking on the action button. The route in the browser looks like:
http://localhost/admin/users/9bb5ab66-7485-4d9e-b806-a9a05abe7f91/projects/9bb7cb42-b9f8-4192-9f6c-14adf7189dbf
Which is absolutely correct. Also user and project with those IDs exist..
The Custom Page:
Sorry - I managed to get it to work
Seems like for the child model I can directly use Route model bindingSorry for bothering you again but even with the custom page and a ChecbkoxList I get problems:
A user has a relation
directPermissions
:
I use a CheckboxList on my Custom page:
I also see the CheckboxList in the frontend and all the permissions (see Screenshot). I thought that there is some kind of model binding and the checkboxes of those permissions the user is already attached to should be checked? I double-checked using artisan tinker
that directPermissions()
actually returns permissions for that user and thats the case..This is the view of the page btw:
I think I found a way. Also I think I found a way in using multiple CheckboxLists using a function in the form's schema as described here:
https://laracasts.com/discuss/channels/filament/how-do-i-create-a-group-of-selects-with-a-foreach-loop-in-filament
This way I don't need to build a custom field nor a custom form and I should be able to directly use the User's relationship.
Thanks for your help!