File Upload · Form
Phoenix Form
<.form for={@form} action={~p"/file-upload/form"} method="post" multipart>
<.file_upload field={@form[:attachment]} class="file-upload">
<:label>Attachment</:label>
<:close>
<.heroicon name="hero-x-mark" />
</:close>
<:error :let={msg}>
<.heroicon name="hero-exclamation-circle" class="icon" />
{msg}
</:error>
</.file_upload>
<.action type="submit" class="button button--accent">Submit</.action>
</.form>
def file_upload_form_page(conn, _params) do
phoenix_form =
Phoenix.Component.to_form(%{"attachment" => nil}, as: :file_upload_phoenix, id: "file-upload-phoenix-form")
render(conn, :file_upload_form_page, phoenix_form: phoenix_form)
end
def file_upload_form_submit(conn, _params) do
conn
|> put_flash(:info, "Submitted")
|> redirect(to: ~p"/file-upload/form#file-upload-form-phoenix")
end
Phoenix Form + Ecto
<.form for={@form} action={~p"/file-upload/form"} method="post" multipart>
<input type="hidden" name="file_upload_validate[_sent]" value="1" />
<.file_upload field={@form[:attachment]} class="file-upload">
<:label>Attachment</:label>
<:close>
<.heroicon name="hero-x-mark" />
</:close>
<:error :let={msg}>
<.heroicon name="hero-exclamation-circle" class="icon" />
{msg}
</:error>
</.file_upload>
<.action type="submit" class="button button--accent">Submit</.action>
</.form>
changeset = MyApp.Form.FileUploadForm.changeset_validate(%MyApp.Form.FileUploadForm{}, %{})
to_form(changeset, as: :file_upload_validate, id: "file-upload-validate-form")
defmodule MyApp.Form.FileUploadForm do
use Ecto.Schema
import Ecto.Changeset
embedded_schema do
field :attachment, :map, virtual: true
end
def changeset(form, attrs \\ %{}) do
cast(form, attrs, [:attachment])
end
def changeset_validate(form, attrs \\ %{}) do
form
|> cast(attrs, [:attachment])
|> validate_attachment_required()
end
defp validate_attachment_required(changeset) do
upload = get_change(changeset, :attachment)
if present_upload?(upload) do
changeset
else
add_error(changeset, :attachment, "can't be blank", validation: :required)
end
end
defp present_upload?(%Plug.Upload{filename: name}) when is_binary(name) and name != "", do: true
defp present_upload?(_), do: false
end
Native HTML Form
<form action={~p"/file-upload/form"} method="post" enctype="multipart/form-data" class="w-full max-w-2xs flex flex-col gap-space">
<input type="hidden" name="_csrf_token" value={Plug.CSRFProtection.get_csrf_token()} />
<input type="hidden" name="_file_upload_form" value="native" />
<.file_upload name="user[avatar]" class="file-upload">
<:label>Avatar</:label>
<:close>
<.heroicon name="hero-x-mark" />
</:close>
</.file_upload>
<.action type="submit" class="button button--accent">Submit</.action>
</form>
def file_upload_form_submit(conn, %{"user" => %{"avatar" => upload}}) do
conn
|> put_flash(:info, "Submitted: avatar=#{file_upload_attachment_label(upload)}")
|> redirect(to: ~p"/file-upload/form#file-upload-form-native")
end
defp file_upload_attachment_label(%Plug.Upload{filename: name}) when name != "", do: name
defp file_upload_attachment_label(_), do: "(none)"