I’m just learning LiveView (0.19) and this took a bit too long to figure out, so I hope this will help someone shorten their search. If there is another way/better way to do this, I’m quite interested to know.
The objective is to use a belongs_to relation as a selection list (in a formatted custom component) for an id to an input for a form. I spent most of my time looking for a phx- event to send on phx-click to update the form input. I don’t fully understand the event model, so my attempts to craft an event that updated the form failed.
Eventually I found this: Form bindings — Phoenix LiveView v0.19.4
There’s a lot to read about how LiveView works, so this section took a while to find. But this works and explicitly looks like this:
Inside my form, I have the field
<.input field={@form[:pin_id]} type="number" id="pin_id" label="Pin" />
<.live_component
module={PsampleWeb.PinLive.Select}
id={:select}
/>
And my Select component looks like:
<div class="overflow-y-auto h-32 border-solid border-red-200 border-2 p-8">
<script>
function sendValue(elementId, value) {
const element = document.getElementById(elementId);
element.value = value;
element.dispatchEvent(new Event('change'))
}
</script>
<.table
id="pin-table"
rows={@streams.pin_collection}
on_click={fn {_id, pin} -> "sendValue('pin_id','#{pin.id}')" end}
>
<:col :let={{_id, pin}} label="Alt"><%= pin.alt %></:col>
</.table>
</div>
For completeness, my Select.mount function:
def mount(socket) do
{:ok, stream(socket, :pin_collection, Conf.list_pin())}
end
In core_components.ex, for .table added the attribute:
attr :on_click, :string, default: nil, doc: "per row onclick"
and later (in the default td of a row generated by phoenix), I added onclick:
phx-click={@row_click && @row_click.(row)}
onclick={@on_click && @on_click.(row)}
And this works. Clicking on a row in the table sends an event to the form input pin_id. However, it does not result in a socket event, so the live view doesn’t see the change until submit or another direct change to another input.
It seems like there might be a way to send a socket event that would have this same effect and that an event handler would be able to enhance the interaction (generically). This does seem like a very common kind of task (using a formatted display of a relation to control an input field), so an easier way to do this (that exists, that I didn’t find, that could be devised) seems of benefit.