live_select icon indicating copy to clipboard operation
live_select copied to clipboard

How can I handle input changes myself

Open Papipo opened this issue 1 year ago • 14 comments

Hi!

First of all, thanks a lot for your work, it's great!

I wanted to create a dynamic hierarchical LiveComponent wrapping LiveSelect. The problem I have is that when an option is selected, it's the Root LiveView (through the form's phx-change) who gets the even.

I tried wrapping the Heex in another form tag but that didn't work. I don't know if there is any other way of having more control over who gets the change event.

There might be an obvious way but I am new to LiveView, sorry.

Thanks in advance, Rodrigo.

Papipo avatar Jan 07 '24 22:01 Papipo

I think a workaround could be to support a form_owner attr

That way I can just wrap my live selects in a nested form tag that owns them.

Papipo avatar Jan 07 '24 23:01 Papipo

Hi @Papipo. You simply have to add the phx-target attribute, as explaned here. Hope it helps.

maxmarcon avatar Jan 08 '24 06:01 maxmarcon

Hi @Papipo. You simply have to add the phx-target attribute, as explaned here. Hope it helps.

I don't think it does because for validation and saving I still need the parent LV to handle the phx-change. I mean, I handle live_select_change on my LiveComponent without issues. The field change-ing is what is problematic.

Papipo avatar Jan 08 '24 07:01 Papipo

It should work. You have to add the phx-target assign to your form component as well. Double check please.

maxmarcon avatar Jan 08 '24 09:01 maxmarcon

I haven't been able yet to fix this. The best solution has been to use send_update from the grandparent liveview (LV -> My Live component wrapper -> LiveSelect is the hierarchy here). To aid on this, I added a __using__ macro to define a handle_event in the LV easily. But it feels white hacky. I think my issue is exactly like this one: https://elixirforum.com/t/liveview-pattern-how-a-live-component-rendered-inside-a-form-should-handle-its-own-internal-form-inputs/44409/5

Still, I think that it might make sense to use a JS hook on my LiveComponent but I'm not sure if there is a way to stop form change events to propagate from the form inputs.

Papipo avatar Jan 08 '24 12:01 Papipo

Really hard to help you without seeing any code. Maybe you can share something?

maxmarcon avatar Jan 08 '24 12:01 maxmarcon

I have invited you to a poc repo which has the same setup and the same issue

Papipo avatar Jan 08 '24 13:01 Papipo

Thanks. I've taken a look. First of all, for your information, nested forms are not valid HTML. They're simply not allowed.

Now, I don't know exactly what your hierarchical live select is supposed to be doing, maybe you can explain the idea behind it so I can suggest some design options?

My guess is that your component is supposed to contain one or multiple live select elements and "intercept" change events from the live select inputs, so that they're handled in the component and not in the parent form's change event handlers. Is this correct?

In this case, in LV, you can achieve this by using custom phx-change and phx-target on the input element (https://hexdocs.pm/phoenix_live_view/form-bindings.html#form-events).

However, live select currently doesn't support this. I could add it though.

Let me know.

maxmarcon avatar Jan 08 '24 18:01 maxmarcon

Yes, that is what I think I need, to intercept the event when an option is chosen without it bubbling up to the form. Thanks and sorry for the poor explanation.

Papipo avatar Jan 08 '24 19:01 Papipo

Ok, then I can add support for custom phx-change / phx-target attributes to live select. I don't know exactly when I'll find the time for it though, it's kind of a busy period for me. But I'll keep this in the back of my mind, promised.

You are of course welcome to contribute a PR if you want to!

maxmarcon avatar Jan 08 '24 19:01 maxmarcon

I can try, apart from supporting the assigns I guess this is mostly js stuff?

Papipo avatar Jan 08 '24 19:01 Papipo

I believe there's no need for changes in the js hook. It should be enough to replicate the assigns in the hidden input elements that are used to contain the value of the selection.

maxmarcon avatar Jan 08 '24 21:01 maxmarcon

Hey @maxmarcon I have this working locally. We need two new assigns:

  • selection_event: Event to be fired when an option is selected. This will prevent a change event bubbling up to the <form>.
  • selection_target: If you have a LV -> LiveComponent -> LiveSelect, you might want to get the selection event in the LiveComponent (that's my use case), so you can pass selection_target={@myself}. Otherwise, the LV will get it. This assign is useless without selection_event.

This is how I have called them, let me know if you'd rather use other names and if you agree with the approach.

BTW, I saw that you are using hidden inputs because there were issues with select fields but I think that's no longer the case.

Papipo avatar Jan 12 '24 14:01 Papipo

Hey @Papipo and sorry for the late reply.

Why do we need a new selection_target assign? LiveSelect already supports phx-target and we can use that one as far as I can see.

For selection_event, in order to remain consistent with LV conventions, I would simply use phx-change. That's the only new assign we need.

Please share your code or create a PR, so we can have a more meaningful conversation about this :)

thanks

maxmarcon avatar Jan 26 '24 14:01 maxmarcon