5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Stimulusを使ってドラッグ&ドロップでファイルアップロード

Last updated at Posted at 2022-03-17

Rails で input[type=file] の入力欄にファイルをドラッグ&ドロップして選択する機能を追加しようとネットを調べてみたのですが、script 要素にべた書きの実装例しか見つからなかったので、Stimulus を使った実装をしてみました。

環境

  • Ruby 3.1.1
  • Ruby on Rails 7.0.2

View

既存のページには、data-controller 属性と data-action 属性と data-*-target 属性を追加するだけなので、ほとんど手を入れずに済みます。

Stimulus 側に file_drop という名前のコントローラを作るので、data-*-target 属性の値や名前もそれに合わせます。

app/views/users/_form.html.erb
  ...
  <div data-controller="file-drop"
      data-action="dragover->file-drop#dragover dragleave->file-drop#dragleave drop->file-drop#drop">
    <%= form.label :image, style: "display: block" %>
    <%= form.file_field :image, 'data-file-drop-target': 'fileUpload' %>
  </div>
  ...

Controller

file_drop_controller.js 中の targets で指定した値(fileUpload)から自動的に fileUploadTarget というプロパティが生成されます。
これは自動で生成されるため、targets の値に file-upload のようなケバブケースは使えません。
'data-file-drop-target': 'file-upload' って書きたかったのですが諦めました。

data-action 属性でイベントとそれに対応するコントローラ#メソッドを指定したものが、ここで呼ばれます。

script 要素にべた書きだと element.addEventListener('dragover', () => {}) としていたところを、ちょっとだけわかりやすく書けるようになります。

app/javascript/controllers/file_drop_controller.js
import { Controller } from '@hotwired/stimulus'

export default class extends Controller {
  static targets = ['fileUpload']

  dragover(e) {
    e.preventDefault()

    // dragover したときに border の色を変える
    this.fileUploadTarget.classList.add('border-primary')
  }

  dragleave(e) {
    e.preventDefault()
    this.fileUploadTarget.classList.remove('border-primary')
  }

  drop(e) {
    e.preventDefault()
    this.fileUploadTarget.classList.remove('border-primary')

    const files = e.dataTransfer.files
    if (typeof files[0] !== 'undefined') {
      this.fileUploadTarget.files = files
    }
  }
}

あとは作成したコントローラを読み込むだけ。

app/javascript/controllers/index.js
import { application } from './application'

import FileDropController from './file_drop_controller'
application.register('file-drop', FileDropController)
5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?