While moving to LiveView 1.0 I encountered the following problem. We integrate flatpickr for date inputs using Clients hooks (e.g. phx-hook).
This library dynamically generates an alternative form input element that allows interaction. The original input (annotated with the phx-hook attribute) is hidden (using the type="hidden" attribute).
After changing to the new way to track used inputs (explained in the changelog and in the docs for Phoenix.Component.used_input?/1) I noticed that inputs with this hook are never marked as unused. This makes the input immediately seem used after a handle_event cycle. In cases where the input is validated as required for example, this makes the input show up with its error markup and validation error, even though an unrelated input has triggered the validation while the date input is untouched.
I’ve posted this before, but I would like to zoom out a bit. I guess there are more JS libraries that use a similar pattern (adding an alternative input field, hide the original, and keep them in sync). I see that hidden fields don’t get a companion parameter with the _unused_ prefix by design: see here. All libraries using a similar pattern should see this change in behaviour with LV 1.0.
Is there another trick that can be used in this case that I’m unaware of? Or is this a limitation of how tracking used inputs work in LiveView 1.0 now?
A quick git blame reveals why hidden fields are not included:
It seems a few weeks ago someone else commented with a similar concern about custom JS inputs using hidden fields.
From what I can tell, fields are considered unused until they receive a change/input event, at which point they receive PHX_HAS_FOCUSED (which from the name one would think means the element received focus, but apparently not). So unless you explicitly dispatch such an event, these JS-controlled fields would never be marked as used at all, right? Until submission, perhaps?
It’s indeed a bit misleading. I think the flatpickr component dispatches change/input events to the original input, so they are picked up by the LiveView JS runtime. I think that mechanism is stil the same from pre LV 1.0.