Why does nothing in this #$%^#$ work as described in docs?
So since my last 4 posted questions didn't get any responses at all, I tried yet something else through blind guessing. The docs seem to say you can dispatch and event and 'catch' it in your component. So i trigger an event:
Livewire.dispatch('coordinatesUpdated', data);
console.log('dispatched updateCoordinates', data);
And the console.log in the browser verifies that the event is dispatched with the appropriate data.
In my component which extends Field I tried adding a $listeners array and function, I also tried adding it to Resources. I even tried based on an example in setUp()
None of them work to 'catch' the updateCoordinates. I can find examples on livewire, but don't know where to put the functions because the documentation for filament gives absolutely no context or full examples of how the various functionalities are supposed to work!
I'm getting really frustrated with this library and the lack of responsiveness to my questions. Not to mention the poor nature of the docs that don't seem to give nearly enough context or detail to know what the smatterings of information they do contain actually pertain to in a codebase. Before I give up on this monstrosity and start broadcasting to everyone to avoid filamentphp like the plague due to the worst-documentation-and-support EVAH, can someone please give me a hint how you make this thing work?!!?
25 Replies
The listeners have to be registered on the livewire component. Neither the field nor the resource are livewire components. The EditResource, CreateResource ListResources page are the actual livewire components.
um ok, then how do you build a custom field as a livewire component? The documentation mentions livewire components on the custom field page but once again gives very little in the way of context or working (complete) examples to give you any clue how the interaction works or how you can create one yourself.
And how then do you use it to cross update the text lat/lon fields and vice versa?
How do you access 'state'? Does it need to be passed through or does filamentphp make it available in javascript? If it is passed through, what goes in each layer? (filament component/blade, vs livewire component/blade vs alpinejs directives)
https://stackoverflow.com/questions/79289526/laravelfilamentphplivewire-on-custom-field-what-goes-where-to-handle-state
Stack Overflow
Laravel+FilamentPHP+Livewire on custom field, what goes where to ha...
I'm trying to figure out the layering withing Laravel using FilamentPHP and livewire components.
I need to have a clickable google maps for a Custom Field in filament php and I'm told that the best...
just reading your stackoverflow link - you want a clickable map that saves lat/long into hidden fields that you can get on save?
Maybe have a look at this old snippet I shared from Filament v2 times:
https://gist.github.com/pxlrbt/7b3b0896db361bae38b22c5cadfd2335
due to the worst-documentation-and-support EVAH, can someone please give me a hint how you make this thing work?!!?You know this is open source and everybody here is giving his time for free?! Maybe you should adjust your expectations But yeah swearing and shitting on other people surely makes them want to help you 🤦🏼♂️
And yet I wouldn't be frustrated to the point of swearing or shitting on other people if my previous 5-6 questions on this forum weren't still sitting with zero responses. Funny how that works.
Anyway, my frustration isn't with forums, but the documentation. Good example in the link above. It gives an example of:
use Illuminate\Database\Eloquent\Model;
class Foo extends Component
{
public function mount(?Model $record = null): void
{
// ... }
// or
public ?Model $record = null; } It says nothing about how $record gets populated, if it needs to be populated, how it can be used, gives no examples of working code or links to jists. It says nothing about how it interacts with other code, if it interacts with other code. Do I just modify $record and the laravel will 'see' it or do I need to trigger an event in javascript and 'catch' it somewhere? And how does this relate to 'state'? Does it relate to state? What is the point of using both $record and $state? What do either mean to Livewire or Alpine.js as relates to filamentphp? I'm left guessing that if I add this to my code, some kind of magic will occur and bam, it will code itself. How are you supposed to use this??? This is not a complete example or instructive information. (it doesn't even completely clarify if 'Component' is a laravel/filament component or a livewire component. I'm left to assume the latter because it's after a statement about livewire components)
// ... }
// or
public ?Model $record = null; } It says nothing about how $record gets populated, if it needs to be populated, how it can be used, gives no examples of working code or links to jists. It says nothing about how it interacts with other code, if it interacts with other code. Do I just modify $record and the laravel will 'see' it or do I need to trigger an event in javascript and 'catch' it somewhere? And how does this relate to 'state'? Does it relate to state? What is the point of using both $record and $state? What do either mean to Livewire or Alpine.js as relates to filamentphp? I'm left guessing that if I add this to my code, some kind of magic will occur and bam, it will code itself. How are you supposed to use this??? This is not a complete example or instructive information. (it doesn't even completely clarify if 'Component' is a laravel/filament component or a livewire component. I'm left to assume the latter because it's after a statement about livewire components)
This is because filament expects you to understand what you are using first.
Livewire documentation explains mount
If you look at any of the code you will see how it is done. Filament isn't here to teach your livewire and laravel. But to offer you a tool which enables it to be a rapid development cycle.
What you are looking for is tutorials on mcreation components which explain in detail each step. And that is what LaravelDaily do.
I am trying to create a user-friendly form for non-computer-literate people to mark locations for a private club. Since non-computer-literate people may-or-may-not have or know how to use GPS systems or even lat/lon coordinate, one option I want to use is a custom google maps visual 'click' field.
I also want to include text fields for latitude and longitude for people who are bright enough to figure out their own coordinates in advance.
And finally I figured including a KML upload would be handy for people who did have a GPS or could use their smart phone, etc.
I would like two-way updating between the map-click field and the lat/lon text fields so if you click the map, it will update the lat/lon text fields. And if you modify the lat/lon text fields it will dispaly the location on the map with a marker.
I would like a one-way update from uploading a kml file that would fill in the lat/lon fields after parsing the xml and then move-or-create a marker on the map at that location so they could visually verify it.
I already have a working, clickable map class-wrapper in javascript with the overlay of the more familiar map used by the club. I already have a working upload field and was able to get the lat/lon to fill in after parsing the xml.
I'm stuck at the moment on how to get coordinates from the non-hydrated map custom field and also to update the map marker.
I have built what you are asking for for a client in the past. It was fairly simple to do.
There is a plugin for the lat/lon from map on the plugins directory.
The KML can be done via a file upload field with afterStateValidated or via parsing it afterwards.
That would all depend on how you have built it... since there are many ways.
Filament is choosing to use Livewire w/alpine js. I've gone through Livewire and alpine js documentation but it doesn't include interaction with filament and the documentation in the filament page doesn't seem to provide enough detail. I have about 30 tabs open in my browser at the moment to various livewire, alpinejs and other documentation but there isn't a 1:1 relationship between the two libraries and how filament php seems to use the two libraries. At least not per my testing.
The points I'm stuck at is mostly with injecting and extracting the information from and to the filament side of things. As mentioned in other comments, I have a working livewire map wrapper. I have at least semi-working alpine.js loading and initializing. I don't know how to get scope and/or record and/or the values I actually 'need' from such a piece in and back out again and I'm not finding detailed enough information in the documentation as to who to do this.
I can't use a simple plugin - I've tried and modifying it to use the custom, bounded, overlayed map has proven to be frustrating as it ultimately breaks the plugin in some way due to the lack of understanding I have for what I just described above - how to get the information both in and out again. (I've been trying such possible solutions going on 10 working days)
Most of the plugins I have found only seem to work 'one way' getting information 'out' of the click. And without documentation as to how they are doing this, I'm left guessing just as much as I seem to be from using the filament (lack-of) documenation.
KML isn't the problem, google maps isn't the problem. Knowing how to pass values in and out again is the problem.
I even tried using a basic 'slider' and was able to get information in and back out again and found the method it used didn't seem to work when I tried to do the same with the map code. That and adding the map broke the slider/interaction somehow - I don't know how.
Filament is choosing too which we are built on for a reason because it's easy.
Your frustrations are just a lack of knowlage, usisng a good editor like phpStorm will allow you to travese through and pick up the extended classes to see how mounting etc works if in doubt. I was in your position as I learnt laravel via filament in the first place.
So passing values you use $get, $set within fields, in custom livewire you declare the properties on the component and just pass them thourhg with wire click etc as per livewire documentation.
What you need to know with custom components is the html is refreshed on actions so the js wouldn't re-fire and likely some of your issues.
But without seeing what you have done we can't see.
OK, I think I see in that link something that might make the job easier or at least less complicated, but it still doesn't give me good details on getting information in and out. Namely referring to directly loading a Livewire component. i.e. I can remove the layer of needing to wrap a custom 'field' around it if I am reading this correctly.
But then if I use Livewire::make('MyComponent', []), there's still a question on how I interact with the lat/lon fields and vice versa.
mount() would seem to allow me to pass in any pre-existing value (on initialization of the map), but changes in the text fields or changes on the map - still not sure how to handshake those in filament
I see for example that I could use:
use Livewire\Component as Livewire;
function (Livewire $livewire) {
// ...
}
But this seems to apply to the current 'field' in the form. So I can't assume I can directly access the component of 'location' (the map) from the afterStateUpdated context of the TextField 'latitude'
So the ideal way here would be to look at existing components like the lat/lon picker.
Mount is only done on php runtime and mounted in place.
What you are now asking is solely livewire passing of data between components as per:
https://laracasts.com/discuss/channels/general-discussion/livewire-passing-data-from-one-component-to-another
Part of the problem I'm running into is that the documentation for things like Livewire and Alpine.js are more specific to interactions within the blade template, not within javascript.
from that example, again mount() would only seem to help me upon initialization of the map. I'm trying to utilize the map as a ->live() component/field and the problem I'm having is in the interaction and passing of data in and out 'after' the map is initilized.
(I think I've figured out how to pass initial values in [to the map] for an 'existing' location. I can't figure out how to communicate between the map/javascript and the filament form fields lat/lon and vice versa)
Is $state something 'built in' to the livewire? e.g. for dependency injection?
i.e. can I do something like:
function mount($state) { .... }?
?
it seems to want something passed in, and again, I don't know how to do that and can't find any examples in the docs.
I tried:
<x-dynamic-component
:component="$getFieldWrapperView()"
:field="$field">
@livewire('gmap-location', [
'state' => $wire.$entangle('{{ $statepath }}')
])
</x-dynamic-component>
And get:
Internal Server Error
ErrorException
Undefined variable $entangle
OK, I made some progress after finding a page that told me how to put the livewire state into the alpine.js finally:
@entangle('livewire-state')
So I can pass the livewire state into my google map wrapper class. Now the problem is the livewire-state doesn't seem to have the custom 'field state' in it anywhere.
aaaaaand I'm no closer to a solution or understanding how the field state is supposed to be passed into and out of livewire/alpine.js components. This has been my whole week!
Another great example, I went to this page:
https://filamentphp.com/docs/3.x/support/assets#asynchronous-alpinejs-components
I followed step-by-step creating the test-component. First it says:
"When you run php artisan filament:assets, the compiled file will be copied into the /public directory."
It didn't....
So I copied the file manually into the public directory.
I then created a new custom form field component and followed it's example for the blade template and I get:
"
Internal Server Error
Error
Object of class Closure could not be converted to string
"
Even following the documentation to the letter, the code doesn't work.
It works. Several of my plugins use this approach. I think it might help you source dive some of the plugins and see how various people are making it all work.
Take some time to understand what other devs are doing.
Do you even need a livewire component for the map? Idk, seems like it could all be done in js with alpine. One thing to consider is that with livewire v3 alpine and LW are automatically entwined. I think a better understanding of how they work will get you close to your desired goal. But, with that said, no one is going to give you copy paste solution for this. Nor, is it going to be easy to offer help without seeing the code base of what you have tried and what isn’t working.
I would also like to give some tips here:
- Setup xdebug to debug PHP code that gets executed;
- Laracast also have some great series on PHP / Alpine / ... as well. Not tutorials mind you (they also have those), but explainers on how the libraries (high-level) work. The way you grow as a developer is to realise everything you need of information is actually in the code (if you take the approach of digging into the libraries source-code, you will learn much faster).
Good luck!
The problem isn't on the php side of things. The interaction I need is in the browser, and unfortunately, the way livewire and alpinejs embed 'code' into html element attributes made it hard to trace those.
I thought the implementation of alpine.js in filamentphp was tied to livewire. At least from what I could glean fromt he docs.
And I don't need a 'copy paste' solution. I need to know the best practices, standard way someone is supposed to modify the state used by filament in the filament implementation of alpinejs. I have yet to see anything anywhere that shows a working example of this that isn't embeded in some 100000 lines-of-code existing library I'm supposed to 'source dive' (without knowing how filament uses alpinejs - it's like being told to go pick through a garbage dump to figure out how pizza is made)
I went through four of the available libraries again. Only one of them (outside of the one I already tried to modify) matches my use case and it's HUGE. It could probably work 'as is' if it only supported image overlay - which, near as I can tell, it does not.
Aaaaaand the method it uses to try to pass in the state is the first one I tried (which did not work)
I should add, underpining all of this, I'm trying to use this as a 'learning' sandbox project. Figuring out how to pass the state to and use it in livewire is the goal, not getting this particular widget to work.
(which is why not being able to find a simple answer is so frustrating and pushing me to consider options other than filament - if all basic issues are going to be this much of an excruciating enema to find the answer, it's a bad sign)
Again, please share more through code. It’s hard to help with only seeing bits and pieces of what you are trying to accomplish.
For starters, $wire.$entangle needs to be in an alpine component. Then $getState probably needs to be $getState() but not sure because I don’t know if you are defining it in the code but not showing that part of the code.
Sad that you need to know so much but don’t have the patience to learn. I can feel you though. Filament is too tempting but requires very good background on Livewire and most importantly a lot of code diving which is in a way imo.
Pro tip: When stuck, try next day. It usually works for me. 😋
🔥
are you able to share this project, or a project that reproduces this issue, on github?
it would be better for me to run this project and focus on the exactly issue that you are mentioning..
treii28 has been warned, this is their first warning.