nallwhy
What is the best way to handle file uploads in a LiveView dynamic form?
In my application, users can upload multiple Contracts as files for a User from a form.
defmodule User do
use Ecto.Schema
import Ecto.Changeset
@primary_key false
embedded_schema do
field :name, :string
embeds_many :contracts, Contract, primary_key: false, on_replace: :delete do
field :file_url, :string
end
end
def changeset(%__MODULE__{} = struct, attrs) do
struct
|> cast(attrs, [:name])
|> cast_embed(
:contracts,
with: &changeset_contract/2,
sort_param: :contracts_sort,
drop_param: :contracts_drop
)
end
def changeset_contract(%__MODULE__.Contract{} = struct, attrs) do
struct
|> cast(attrs, [:file_url])
end
end
I want to handle this using the Dynamic Form feature of LiveView.
defmodule MyAppWeb.Live do
...
@impl true
def render(assigns) do
~H"""
<.simple_form for={@user_form} phx-change="validate" phx-submit="submit">
<.input label="name" field={@user_form[:name]} />
<.inputs_for :let={fc} field={@user_form[:contracts]}>
<input type="hidden" name="user[contracts_sort][]" value={fc.index} />
<.live_file_input upload={???} /> # <-- this is the problem
<.label>
<input type="checkbox" name="user[contracts_drop][]" value={fc.index} class="hidden" />
<.icon name="hero-x-mark" class="w-6 h-6 relative top-2" /> remove
</.label>
</.inputs_for>
<label class="block cursor-pointer">
<input type="checkbox" name="user[contracts_sort][]" class="hidden" />
<.icon name="hero-plus-circle" class="mr-1 align-text-bottom" />add more
</label>
<:actions>
<.button>Submit</.button>
</:actions>
</.simple_form>
end
end
In the validation event, it’s possible to dynamically add file uploads using allow_upload/3 . However, due to Contracts being dynamically created and deleted, the index keeps changing (what was originally the 3rd index becomes the 2nd index if the 1st index is deleted), making it difficult to track. I would like to use the _persistent_id, which does not change, but it’s hard to track since _persistent_id is unknown at the point when the input is added.
What is the best way to handle file uploads in a LiveView dynamic form?
First Post!
codeanpeace
Have you tried using the :ref field on the UploadEntry struct?
<%!-- render each avatar entry --%> <%= for entry <- @uploads.avatar.entries do %> ... <%!-- a regular click event whose handler will invoke Phoenix.LiveView.cancel_upload/3 --%> <button type="button" phx-click="cancel-upload" phx-value-ref={entry.ref} aria-label="cancel">×</button>Cancel an entry
Upload entries may also be canceled, either programmatically or as a result of a user action. For instance, to handle the click event in the template above, you could do the following:
@impl Phoenix.LiveView def handle_event("cancel-upload", %{"ref" => ref}, socket) do {:noreply, cancel_upload(socket, :avatar, ref)} end
source: LiveView Uploads guide
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









