Multiple live_file_input on one page - how to pass parameter?

So, I am trying to use live_file_input in which I have the following scenario:

Category1
Category2
Category3
Category4

In each category, which is an accordion view, the user can add an upload.

So, for each accordion, I have an input form with a separate id on each form, and a hidden input field to convey the data.

However, when the image from category 3 is uploaded, the

validate-form handler gets the hidden input from category 1.

I’d like to figure out how to EITHER:

Correctly associate the parameters to the validate event handler with the form it is coming from,

OR

Directly pass the id of the category with the upload event.

The image uploading all works fine, the problem is associating c.id with the image once it is delivered.

Note that this in a sub-component in which the parent @uploads.image has been passed in as @upload.

This is the code that is iterated on.

                  <form
                    id={"upload-cimg-" <> to_string(c.id)}
                    phx-submit="save-classifier-img"
                    phx-change="validate-classifier-img"
                  >
                    <div phx-drop-target={@upload.ref} class="items-center text-center">
                      <span class="block">Add a reference image:</span>
                      <label for={@upload.ref}>
                        <div class="h20 w20">
                          <.icon name="hero-plus-circle" class="h-20 w-20 mt-2 text-gray-400" />
                        </div>
                      </label>
                    </div>
                    <input type="hidden" name="cid" value={c.id} />
                    <.live_file_input upload={@upload} class="hidden" />
                  </form>

I added an id to the live_file_input element in the hopes that this might get passed through to upload completion, but the id is overwritten by phoenix somewhere. Moreover, all live_file_inputs are getting the same id. Presumably that is being driven by the upload.ref.

It feels like I need to dynamically create a distinct upload target for every possible live_file_input? But that would be a sort of insane solution to parameterizing a form…

I solved something similar by using a dedicated allow_upload, one for each category, in your case

Here is an example for multiple languages…

  defp assign_embed_medium(socket, languages) do
    Enum.reduce(languages, socket, fn language, socket ->
      socket
      |> allow_upload(to_key(language),
        accept: ~w(.mp4),
        max_entries: 1,
        auto_upload: true,
        # Provide a limit, as the default is low
        max_file_size: @max_file_size,
        chunk_size: @chunk_size
      )
    end)
  end

I can even change the languages dynamically, and it still works

1 Like

I was hoping not to do this because the classifers are dynamic and users can add them, which makes for a more complex orchestration. I am currently attempting using a live component to wrap state for each instance. I’ll report how that goes.

As the languages are in my case dynamic too… user can add, or remove a language

So, my solution for this scenario was to use a Live Component rather than a function component to associate the state of the individual item with a dedicated allow-upload mounted on the component, rather than a shared allow-upload mounted on the page.

@kokolegorille effictively did the same thing by managing dynamic allow-uploads at the page level.

I don’t love either solution because in my mind the meta data associated with an upload should be independent of the ability to configure upload mechanics and parameters. But it works, and I think the Live component solution is less fussy than managing allow-upload configurations on the page-level socket.