Koszal

Koszal

Here is a simple component to show a modal dialog:

def modal_access(assigns) do
  ~H"""
  <.modal id="modal-access" class="phx-modal"}>
    <p>Request access to this tool?</p>
  </.modal>
  """
end

The modal is displayed after clicking a button.

  <button
    phx-click={show_modal("modal-access")}
    phx-data-tool-tag={@tool_tag}
  >

There are many tool buttons on the page and the user can click any of them.

This all works fine.

Now, inside the modal I would like to change

  <p>Request access to this tool?</p>

to

  <p>Request access to {@tool_name}?</p>

and this is where I get lost.

I did not think it was good idea to create multiple modals - one for each tool. (If I did that I could inject a different tool_name in the same loop that creates buttons.)

I was hoping I could let the server know which tool/button was clicked, then translate tool_tag to tool_name on the server side, and put it in the assigns (and then display (or update(?) the modal window).

How should I do it?

I have tried a few things, for example adding JS.push:

  phx-click={JS.push("did-select-modal") |> show_modal("modal-access")}

However, I don’t see any data reaching the server. (Plus I am not really sure how that should work - would I have to embed a live-view in the modal window?)

I am probably misunderstanding/missing some core concepts. Any guidance would be much appreciated!

K.

Showing Posts 1 to 3

Koszal

Koszal OP

I have stitched something together after a fair amount of head scratching.

  1. First, there is live_render, which allows instantiating a live view inside a functional component.

    <%= live_render(@conn, MyApp.ToolAccessModalDialogLive %>

    (Not really sure why the syntax is <%= ... %> rather than a usual component instantiation.)

  2. Now that I have a live view to send events to, I can use JS.push(...) However, I need to specify the target: JS.push(... target: ...) because the button that triggers showing of the modal dialog is outside that dialog.

  3. Using target: "modal-access" (see the snippet in my original question) does not work because "modal-access" is the id of the modal dialog, the actual live-view is nested inside.

  4. I specified the id in <%= live_render(@conn, .., id: ...) but that does not work either because the id gets overwritten with the auto-generated one.

  5. In the end I created a dummy <div id="receiver"> inside the live view and now I can JS.push events to that div. That works!

  6. The last problem was getting rid of the layout injected to the live_render-ed element. I ended up creating a new helper in MyAppWeb and then in my module I replaced

use MyAppWeb, :live_view

with

use MyAppWeb, :live_render

where live_render is like live_view but without the layout:

  def live_render do
    quote do
      use Phoenix.LiveView,
        layout: false

      unquote(html_helpers())
    end
  end

K.

sodapopcan

sodapopcan

Hey @Koszal!

Just to confirm, I take it you aren’t able to just make the whole page a LiveView? I feels a little heavy handed to have a LiveView just for managing modal data, but maybe not. Is there going to be more stuff than just the “Request access” message in them?

If you really need to get the data from the server, it may be better to sett up a JSON endpoint (again, assuming you must use with classic controllers).

There are ways to do this clientside as well and I’m happy to give you some ideas there if that’s an option.

A couple of other things:

  • The <%= ... %> syntax is used because live_render isn’t a component, it’s just a regular function call. A compont is a function that takes a single argument of assigns which you can see live_render is not.
  • Another way to remove the layout is to return a 3-tuple from mount/3 with the layout: false option:
    def mount(_params, _session, socket) do
      {:ok, socket, layout: false}
    end
    
Koszal

Koszal OP

just make the whole page a LiveView

Yes, I had come to the same conclusion as I was thinking this over!

The way I implemented it ended up particularly bad - the live view process starts running when the page loads even though it is possible that the user will never use the modal. There are already some elements on the page that could be live so turning the whole thing into a live view makes perfect sense.

(OTOH - since this is purely an exploration project - I would be curious to know how I could start the live view on demand - only after the ‘Show dialog’ button is clicked. That probably requires some JS trickery?)

live_render isn’t a component

Yes - I get it now. Both are functions but the signatures are different. To be a componet, the function must take assigns.

return a 3-tuple from mount/3 with the layout: false option:

Ah - indeed - mount! I knew I saw layout: false somewhere in the documentation…

Thank you very much for the pointers!

K.

— All posts loaded —

Where Next? Top

Trending in Questions Top

Blokh
Hey guys, I’ve got a huge CSV ( around 10 GB ) that needs to be processed hourly Do you guys have any suggestions what is the best prac...
New
RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
kszambelanczyk
Hello! Could someone please give me a help/sample code, how to delete a file from s3 using waffle/waffle_ecto from Phoenix app. I creat...
New
RemyXRenard
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
samoloth
Hi, I’ve just set up an application with ash_authentication. There is only magic link strategy for now, so there is no confirmation add o...
New
FlyingNoodle
If a change or preparation module uses Ash.Changeset.get_argument/2 or Ash.Query.get_argument/2 (or any of the other get_argument functio...
New

Other Trending Topics Top

mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge &amp; Solve. They are GUI (Emerge) and State management (S...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews