😸

ファイルフィールドを非表示にして、選択された画像のプレビューを表示する方法

2024/03/08に公開

内容

PF作成の時にメンターさんに教えて頂いたことをいつもで引き出せるように書いておこうと思います。
ファイルフィールドを非表示にして、選択された画像のプレビューを表示する方法です。

form.html.erb

<%= form_with model: user, method: :patch, local: true do |f| %>
    <%= f.file_field :profile_image, class: "d-none", onchange: "previewImage(this);" %>
    <% if user.profile_image.attached? %>
    <%= image_tag user.profile_image, class: "open-file-field", id: "preview" %>
    <% else %>
    <%= image_tag "user_no_image.jpg", class: "open-file-field", id: "preview" %>
    :
    :

f.file_fieldは、アップロード用のファイルフィールドを生成します。:profile_imageはこのフィールドがモデルのprofile_image属性に関連付けられていることを示しています。

class: "d-none"は、このファイルフィールドを非表示にするためのCSSクラスです。

onchange: "previewImage(this);"は、ファイルが選択されたときにJavaScript関数previewImageを呼び出すようにしてます。

<% if user.profile_image.attached? %>:
ユーザーのprofile_imageが添付されているかどうかを確認しています。

<%= image_tag user.profile_image, class: "open-file-field img-fluid user-profile-image", id: "preview" %>:
classやidを指定してスタイルや識別子を設定しています。

form.html.erb

    :
<script>
  $(".open-file-field").on("click", () => {
    $("#user_profile_image").click();
    return false;
  });

  function previewImage(obj)
  {
  	var fileReader = new FileReader();
  	fileReader.onload = (function() {
  		document.getElementById('preview').src = fileReader.result;
  	});
  	fileReader.readAsDataURL(obj.files[0]);
  }
</script>

$(".open-file-field").on("click", () => {...});:
クリックされると、$("#user_profile_image").click();が呼び出されます。これにより、#user_profile_imageというIDを持つファイルフィールドがクリックされたことになります。

return false;は、クリックイベントが親要素に伝播せず、デフォルトの動作が抑制されるようにします。これにより、通常のファイルフィールドが表示されず、代わりにカスタムな要素がクリックされたことになります。

function previewImage(obj) {...}:
この関数は、ファイルが選択されたときに呼び出されます。通常、これはファイルフィールドに新しいファイルが選択されたときに発生します。FileReaderオブジェクトを作成して、選択されたファイルの内容を読み込みます。

fileReader.onloadは、ファイルの読み込みが完了したときに実行されるコールバック関数を指定しています。読み込んだファイルのデータURLを取得し、それを画像のプレビューとして表示します。
具体的には、document.getElementById('preview').src = fileReader.result;によってプレビュー画像の src 属性が設定されます。

まとめ

JavaScriptでの実装機能になります。ここらへんの知識はもっと深堀りしないといけないなと思います。

Discussion