簡體   English   中英

為什么 Phoenix LiveView 表單中的 file_input 不返回 %Plug.Upload{}?

[英]Why doesn't the file_input in the form on a Phoenix LiveView return a %Plug.Upload{}?

我在 Phoenix LiveView 中有一個表單,其中包含一個file_input 我想用它來允許用戶上傳圖像。 我無法理解表單發送到我的后端的內容,以及我可以用它做什么。 我期望圖像文件的 %Plug.Upload{} 表示,如文檔中所述,但我只是得到"[object File]"

請注意,我沒有使用變更集支持表單,因為我沒有使用 Ecto:

<%= f = form_for :post, "#", phx_submit: :create_post, phx_change: :image_attach, multipart: true %>
  <%= hidden_input f, :user_id, value: @current_user.account_id %>
  <%= textarea f, :message, class: "social-post-box", placeholder: "Something on your mind?" %>
  <div class="post-submit-container">
    <%= submit "Post", class: "post-submit" %>
    <label for="post_image" class="post-submit-image"></label
    <%= file_input f, :image %      
  </div>
</form>

我在 LiveView 模塊中有一個處理程序來處理提交的表單,當我檢查圖像上傳時,我看到"[object File]"

def handle_event("create_post", %{"post" => post_params}, socket) do
  IO.inspect post_params["image"]
  {:noreply, socket}
end

我試着在這個位置撬,這樣我就可以運行i post_params["image"] ,它解釋了這個對象是一個位串,即只是一個二進制文件。 所以它實際上只是文本“[object File]”,甚至根本不是文件?

我從我的表格中收到了什么? 為什么不是%Plug.Upload{} 如何實現將上傳的圖片保存到本地文件系統的目標?

正如@sbacaro 指出的那樣,LiveView 表單尚不支持文件上傳。

更多信息:

我實現了一個 Javascript 解決方法來手動發送表單而不刷新頁面(以便 LiveView 的其他部分繼續正常運行)。

但是,Phoenix 在 LiveViews 中處理 CSRF 令牌的方式也存在問題。 事實證明,當套接字從客戶端連接時,LiveView 會創建一個新令牌,並且該令牌不會被監聽表單 POST 的控制器識別。 要解決此問題,您需要手動將令牌傳遞到 LiveView。

總體而言,這種解決方法工作正常,但我希望將來有一天有人會在這里指出文件上傳已在 LiveViews 中獲得支持並分享一種更簡單的方法。

我的表格現在看起來像這樣。 請注意 csrf 令牌的手動規范:

<%= f = form_for :post, Routes.profile_path(UdsWeb.Endpoint, :post_social, @current_user.username), [phx_change: :image_attach, multipart: true, id: "social-timeline-form", csrf_token: @csrf_token] %>
  <%= hidden_input f, :user_id, value: @current_user.account_id %>
  <%= textarea f, :message, class: "social-post-box", placeholder: "Something on your mind?" %>
  <div class="post-submit-container">
    <%= submit "Post", class: "post-submit" %>
    <label for="post_image" class="post-submit-image"></label>
    <%= file_input f, :image %>
  </div>
</form>

我從一個普通的 eex 模板中渲染 LiveView。 請注意,我在這里手動指定了 csrf 令牌:

<%= Phoenix.LiveView.live_render(@conn, UdsWeb.ProfileTimelineLive, session: %{current_user: @current_user, csrf_token: Phoenix.Controller.get_csrf_token()}, container: {:div, class: "feed"}) %>

時間線模塊有一個掛載函數,可以將 csrf 令牌加載到套接字分配中:

def mount(%{current_user: current_user, csrf_token: csrf_token}, socket) do
  {:ok, assign(socket, current_user: current_user, csrf_token: csrf_token)}
end

用於手動控制表單提交的 JS 並不是很特別,但它是:

function handleSocialTimelinePost(e) {
  e.preventDefault();
  let form = document.querySelector("#social-timeline-form");
  let formData = new FormData(form);
  let username = formData.get("post[username]");
  let request = new XMLHttpRequest();
  request.open("POST", `/profile/${username}`);
  request.send(formData);
}

document.querySelector("#social-timeline-form button.post-submit").onclick = handleSocialTimelinePost;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM