Recommended way to initiate a LiveComponent Modal from another LiveComponent?

This has already been partly answered here: Recommended way to open a LiveComponent Modal *from* another LiveComponent?

However, I find the comments after the solution to be interesting, as I sit with the exact same problem now, and im wondering how to solve this “the Phoenix LiveView way”.

It seems pretty clear cut, and it was also my gut feeling, that the liveview should handle navigation.
However when you have some advanced views, with loads of components on screen, the liveview gets really cluttered.

My example is that I have a header with some information, and a tabbed view.
Each tab does Crud on different data types. The create and edit, prompts a modal for inputting data, before saving.

What is the correct way to compose something like this? How would you divide responsibilities?
Currently the “component” is self contained, and displays the modals, and handles the data updating.
That feels anti pattern, based on the above thread.
What is the correct way then? Passing button presses to the liveview, to display the modal, handle all data updating in the modal, and when it closes, update the component?

I feel like this very quickly ends up with having the liveview manage state for all child components? (Or am I just overthinking that?)

Could the component the a Child liveview instead? Or should It still then only be the parent live views responsibility?

I Could also have multiple live views, each implementing the “header” and “tab” component, and just displaying their “version of it” and its own content below. And then the tab bar handles navigating between the live views. (Feels really clunky, and not intuitive when looking at the screen, but would work I guess)

Any comments, or resources that describe how to work with the problems above?

1 Like

I think you’re overthinking the problem. If one of the visible components opens a modal, you want that component to be responsible for the modal and that’s how it can be.

But with LV usually opening modals are considered page navigation, and therefore to open the modal the components needs to inform the parent LV to go to that changed URL, so URL as well as the parent LV state is updated, the updated LV state is then passed down again into the component, so it renders the modal.

Besides the fact that the URL changed the parent LV doesn’t need to be involved in any of the modal handling. It doesn’t even need to know that this URL it changed to will open a modal. The change in path/live_action/… could mean anything to the rendered components on the page.

1 Like

The parent LV kind of has to be aware that its opening the modal, as it has to change to the correct URL, that triggers that, or am I missing something?

Edit: Is it just me or doesn’t it feel clunky, for a component to tell its parent: Hey please show my modal?

You don’t need to tell it “Please show my modal”. You’d tell it “Please go to this url here”. The url will then e.g. result a new live_action based on your router, which you can pass down to components, which can then decide what needs to happen based on that new live_action.

But if I from the component, tell the liveview, go here, then the component is aware of where it is.

You can pass in the required data or a callback into the component to built it up. You can also leave it completely in the parent to construct the url based on having received the request to go to “the modal url”.

Granted you’re argueing you’d like the modal to open the modal on its own it would need to be aware of the URL in the first place anyways I’d imagine.

Its a crud component, where the edit/new lives in a modal, and I feel like the component should own that modal (not sure about that though)
I don’t really want it to be aware of the URL, but as its best practice to update the url when you navigate, I couldn’t figure out a better way, than, like you say, tell the parent to update the url, pass the new state into component, and then have it show the modal.
(Handling this correctly, also gets harder, the deeper nested a component is)

How does passing in a callback work/look like?