LiveView는 서버에 직접 업로드는 물론 클라이언트에서 클라우드에 직접 외부 업로드에 대한 진행 상황과 함께 대화형 파일 업로드를 지원합니다.
Accept specification - 허용되는 파일 유형, 최대 항목 수, 최대 파일 크기 등을 정의합니다. 클라이언트가 파일을 선택하면 파일 메타데이터가 사양에 대해 자동으로 검증됩니다. Phoenix.LiveView.allow_upload/3을 참조하십시오.
Reactive entries - 업로드는 소켓의 @uploads 할당에 채워집니다. 항목은 진행 상황, 오류, 취소 등에 자동으로 응답합니다.
Drag and drop - phx-drop-target 속성을 사용하여 활성화합니다. Phoenix.LiveView.Helpers.live_file_input/2를 참조하십시오.
일반적으로 마운트 시 allow_upload/3을 통해 업로드를 활성화합니다.
@impl Phoenix.LiveView
def mount(_params, _session, socket) do
{:ok,
socket
|> assign(:uploaded_files, [])
|> allow_upload(:avatar, accept: ~w(.jpg .jpeg), max_entries: 2)}
end
지금은 그게 다야! 나중에 일부 양식 및 업로드 관련 콜백을 구현하기 위해 LiveView로 돌아올 것이지만 업로드와 관련된 대부분의 기능은 템플릿에서 발생합니다.
Phoenix.LiveView.Helpers.live_file_input/2 파일 입력 생성기를 사용하여 업로드용 파일 입력을 렌더링합니다.
<%# lib/my_app_web/live/upload_live.html.heex %>
<form id="upload-form" phx-submit="save" phx-change="validate">
<%= live_file_input @uploads.avatar %>
<button type="submit">Upload</button>
</form>
중요: 양식에서 phx-submit 및 phx-change를 바인딩해야 합니다.
live_file_input/2를 사용하면 파일 입력에 추가 속성을 설정할 수 있지만 id, accept 및 multiple과 같은 많은 속성은 allow_upload/3 사양에 따라 자동으로 설정됩니다.
템플릿에 대한 사후 업데이트는 최종 사용자가 파일 입력과 상호 작용할 때 발생합니다.
업로드는 소켓의 @uploads 할당에 채워집니다. 허용된 각 업로드에는 allow_upload/3 사양의 :max_entries 값에 관계없이 항목 목록이 포함됩니다. 이러한 항목 구조에는 진행률, 클라이언트 파일 정보, 오류 등을 포함하여 업로드에 대한 모든 정보가 포함됩니다.
주석이 달린 예를 살펴보겠습니다.
<%# lib/my_app_web/live/upload_live.html.heex %>
<%# use phx-drop-target with the upload ref to enable file drag and drop %>
<section phx-drop-target={@uploads.avatar.ref}>
<%# render each avatar entry %>
<%= for entry <- @uploads.avatar.entries do %>
<article class="upload-entry">
<figure>
<%# Phoenix.LiveView.Helpers.live_img_preview/2 renders a client-side preview %>
<%= live_img_preview entry %>
<figcaption><%= entry.client_name %></figcaption>
</figure>
<%# entry.progress will update automatically for in-flight entries %>
<progress value={entry.progress} max="100"> <%= entry.progress %>% </progress>
<%# a regular click event whose handler will invoke Phoenix.LiveView.cancel_upload/3 %>
<button phx-click="cancel-upload" phx-value-ref={entry.ref} aria-label="cancel">×</button>
<%# Phoenix.LiveView.Helpers.upload_errors/2 returns a list of error atoms %>
<%= for err <- upload_errors(@uploads.avatar, entry) do %>
<p class="alert alert-danger"><%= error_to_string(err) %></p>
<% end %>
</article>
<% end %>
<%# Phoenix.LiveView.Helpers.upload_errors/1 returns a list of error atoms %>
<%= for err <- upload_errors(@uploads.avatar) do %>
<p class="alert alert-danger"><%= error_to_string(err) %></p>
<% end %>
</section>
예제의 섹션 요소는 :avatar 업로드를 위한 phx-drop-target 역할을 합니다. 사용자는 파일 입력과 상호 작용하거나 요소 위에 파일을 놓아 새 항목을 추가할 수 있습니다.
업로드 항목은 파일이 양식 입력에 추가될 때 생성되며 업로드가 성공적으로 완료된 후 사용될 때까지 각각 존재합니다.
유효성 검사는 allow_upload/3에 지정된 조건에 따라 자동으로 발생하지만 앞서 언급했듯이 유효성 검사를 수행하려면 양식에 phx-change를 바인딩해야 합니다. 따라서 최소한 최소한의 콜백을 구현해야 합니다.
@impl Phoenix.LiveView
def handle_event("validate", _params, socket) do
{:noreply, socket}
end
allow_upload/3 사양과 일치하지 않는 파일 항목에는 오류가 포함됩니다. Phoenix.LiveView.Helpers.upload_errors/2 및 자체 도우미 함수를 사용하여 친숙한 오류 메시지를 렌더링합니다.
def error_to_string(:too_large), do: "Too large"
def error_to_string(:not_accepted), do: "You have selected an unacceptable file type"
모든 항목에 영향을 주는 오류 메시지의 경우 Phoenix.LiveView.Helpers.upload_errors/1 및 자체 도우미 함수를 사용하여 친숙한 오류 메시지를 렌더링합니다.
def error_to_string(:too_many_files), do: "You have selected too many files"
업로드 항목은 프로그래밍 방식으로 또는 사용자 작업의 결과로 취소될 수도 있습니다. 예를 들어 위의 템플릿에서 클릭 이벤트를 처리하려면 다음을 수행할 수 있습니다.
@impl Phoenix.LiveView
def handle_event("cancel-upload", %{"ref" => ref}, socket) do
{:noreply, cancel_upload(socket, :avatar, ref)}
end
최종 사용자가 live_file_input/2를 포함하는 양식을 제출하면 JavaScript 클라이언트는 양식의 phx-submit 이벤트에 대한 콜백을 호출하기 전에 먼저 파일을 업로드합니다.
phx-submit 이벤트에 대한 콜백 내에서 Phoenix.LiveView.consume_uploaded_entries/3 함수를 호출하여 완료된 업로드를 처리하고 관련 업로드 데이터를 양식 데이터와 함께 유지합니다.
@impl Phoenix.LiveView
def handle_event("save", _params, socket) do
uploaded_files =
consume_uploaded_entries(socket, :avatar, fn %{path: path}, _entry ->
dest = Path.join([:code.priv_dir(:my_app), "static", "uploads", Path.basename(path)])
# The `static/uploads` directory must exist for `File.cp!/2` to work.
File.cp!(path, dest)
{:ok, Routes.static_path(socket, "/uploads/#{Path.basename(dest)}")}
end)
{:noreply, update(socket, :uploaded_files, &(&1 ++ uploaded_files))}
end
참고: 클라이언트 메타데이터는 신뢰할 수 없지만 서버에 직접 업로드를 수행할 때 각 청크가 수신될 때 최대 파일 크기 유효성 검사가 시행됩니다.
이 가이드의 LiveView의 전체 예:
# lib/my_app_web/live/upload_live.ex
defmodule MyAppWeb.UploadLive do
use MyAppWeb, :live_view
@impl Phoenix.LiveView
def mount(_params, _session, socket) do
{:ok,
socket
|> assign(:uploaded_files, [])
|> allow_upload(:avatar, accept: ~w(.jpg .jpeg), max_entries: 2)}
end
@impl Phoenix.LiveView
def handle_event("validate", _params, socket) do
{:noreply, socket}
end
@impl Phoenix.LiveView
def handle_event("cancel-upload", %{"ref" => ref}, socket) do
{:noreply, cancel_upload(socket, :avatar, ref)}
end
@impl Phoenix.LiveView
def handle_event("save", _params, socket) do
uploaded_files =
consume_uploaded_entries(socket, :avatar, fn %{path: path}, _entry ->
dest = Path.join([:code.priv_dir(:my_app), "static", "uploads", Path.basename(path)])
File.cp!(path, dest)
{:ok, Routes.static_path(socket, "/uploads/#{Path.basename(dest)}")}
end)
{:noreply, update(socket, :uploaded_files, &(&1 ++ uploaded_files))}
end
defp error_to_string(:too_large), do: "Too large"
defp error_to_string(:too_many_files), do: "You have selected too many files"
defp error_to_string(:not_accepted), do: "You have selected an unacceptable file type"
end