View Source Backpex.Fields.Upload (Backpex v0.1.1)
A field for handling an upload.
Warning
This field is in beta state. Use at your own risk.
Options
:upload_key
- Required identifier for the upload field.:accept
- Required filetypes that will be accepted.:max_entries
- Required number of max files that can be uploaded.:max_file_size
- Optional maximum file size in bytes to be allowed to uploaded. Defaults 8 MB (8_000_000
).:list_files
- Required function that returns a list of all uploaded files.:file_label
- Optional function to get the label of a single file.:consume
- Required function to consume file uploads and handle changes in the item before it is saved (e.g. append file paths).:remove
- Required function to remove a specific file.
Example
Single File
@impl Backpex.LiveResource
def fields do
[
avatar: %{
module: Backpex.Fields.Upload,
label: "Avatar",
upload_key: :avatar,
accept: ~w(.jpg .jpeg),
max_entries: 1,
max_file_size: 12_000_000,
consume: &consume_avatar/3,
remove: &remove_avatar/2,
list_files: &list_files_avatar/1,
render: fn
%{value: ""} = assigns -> ~H"<%= Backpex.HTML.pretty_value(@value) %>"
assigns -> ~H'<img class="w-5 h-5 rounded-full" src={avatar_file_url(@value)} />'
end
},
]
end
defp avatar_static_dir, do: Path.join(["uploads", "user", "avatar"])
defp avatar_file_url(file_name) do
static_path = Path.join([avatar_static_dir(), file_name])
Phoenix.VerifiedRoutes.static_url(MyAppWeb.Endpoint, "/" <> static_path)
end
defp avatar_file_name(entry) do
[ext | _] = MIME.extensions(entry.client_type)
"#{entry.uuid}.#{ext}"
end
# will be called in order to display files when editing item
defp list_files_avatar(%{avatar: ""}), do: []
defp list_files_avatar(%{avatar: avatar}), do: [avatar]
# will be called to consume avatar
# you may add completed file upload paths as part of the change in order to persist them
# you have to return the (modified) change
defp consume_avatar(socket, _resource, %{} = change) do
consume_uploaded_entries(socket, :avatar, fn %{path: path}, entry ->
file_name = avatar_file_name(entry)
dest = Path.join([:code.priv_dir(:my_app), "static", avatar_static_dir(), file_name])
File.cp!(path, dest)
{:ok, avatar_file_url(file_name)}
end)
case uploaded_entries(socket, :avatar) do
{[] = _completed, []} -> change
{[entry | _] = _completed, []} -> Map.put(change, "avatar", avatar_file_name(entry))
end
end
def remove_avatar(resource, _target) do
Repo.get_by!(User, id: resource.id)
|> User.changeset(%{avatar: ""})
|> Repo.update!()
[]
end
Multiple Files
@impl Backpex.LiveResource
def fields do
[
gallery: %{
module: Backpex.Fields.Upload,
label: "Gallery",
upload_key: :gallery,
accept: ~w(.jpg .jpeg),
max_entries: 5,
list_files: &list_files_gallery/2,
consume: &consume_gallery/3,
remove: &remove_gallery/3,
}
]
end
defp gallery_static_dir, do: Path.join(["uploads", "user", "gallery"])
defp gallery_file_url(file_name) do
static_path = Path.join([gallery_static_dir(), file_name])
Phoenix.VerifiedRoutes.static_url(MyAppWeb.Endpoint, "/" <> static_path)
end
defp gallery_file_name(entry) do
[ext | _] = MIME.extensions(entry.client_type)
"#{entry.uuid}.#{ext}"
end
# will be called to consume uploads
# you may add completed file upload paths as part of the change in order to persist them
# you have to return the (modified) change
def consume_gallery(socket, item, %{} = change) do
consume_uploaded_entries(socket, :gallery, fn %{path: path}, entry ->
file_name = gallery_file_name(entry)
dest = Path.join([:code.priv_dir(:my_app), "static", gallery_static_dir(), file_name])
File.cp!(path, dest)
{:ok, gallery_file_url(file_name))}
end)
{completed, []} = uploaded_entries(socket, :gallery)
file_names = Enum.map(completed, fn entry -> gallery_file_name(entry) end)
file_names =
case item do
%{id: id} when is_binary(id) ->
(Repo.get_by!(Event, id: id) |> Map.get(:gallery)) ++ file_names
_ ->
file_names
end
Map.put(change, "gallery", file_names)
end
# will be called in order to display files when editing item
def list_files_gallery(%{gallery: gallery}), do: gallery
# will be called when deleting certain file from existing item
# target is the key you provided in list/2
# remove files from file system and item, return new file paths to be displayed
def remove_gallery(item, target) do
element = Repo.get_by!(Event, id: item.id)
file_paths =
Map.get(element, :gallery)
|> Enum.reject(&(&1 == target))
Event.changeset(element, %{gallery: file_paths})
|> Repo.update!()
file_paths
end
Summary
Functions
Calls field option function to get label from filename. Defaults to filename.
Maps uploaded files to keyword list with identifier and label.
Functions
Calls field option function to get label from filename. Defaults to filename.
## Examples
iex> Backpex.Fields.Upload.label_from_file(%{file_label: fn file -> file <> "xyz" end}, "file")
"filexyz"
iex> Backpex.Fields.Upload.label_from_file(%{}, "file")
"file"
Maps uploaded files to keyword list with identifier and label.
## Examples
iex> Backpex.Fields.Upload.map_file_paths(%{list_files: fn item -> item.file_paths end}, %{file_paths: ["xyz.png"]})
[{"xyz.png", "xyz.png"}]