Web Marina

日々の業務や勉強などで得た知識をアウトプットしていきます。

【jQuery】要素をコピーする

f:id:song-of-life1352607:20180113005923j:plain

こんにちは、マリンです。

今回は要素をコピーする方法をご紹介しようと思います。

概要

ユーザー一覧を表示しているテーブルの行にコピーボタンを表示。

そのボタンを押すとその行のコピーを直下に挿入します。

userモデルにはnameとemailのカラムがあるとします。

コントローラには@users = User.allを記述しておきます。


ソースコード

views/users/index.html.erb

<table>
  <tbody>
    <% @users.each do |user| %>
      <tr class="copy-row">
        <td><%= user.name %></th>
        <td><%= user.email %></th>
        <td><%= link_to 'copy', "#", class: 'copy-user' %></td>
      </tr>
    <% end %>
  </tbody>
</table>

<script>
  users.copy();
</script>




assets/javascripts/users.coffee

class UsersController
  copy: ->
    $('.copy-user').on 'click', () ->
      currentRow = $(@).parents('.copy-row')
      currentRow.clone(true).innsertAfter(currentRow)
      false
this.users = new UsersController

解説

HTML

まずはビューの方の解説です。

あまり説明することはないのですが...


<tr class="copy-row">

行全体をコピー対象にするためtrにクラスをつけます。

trだけでも良いのですが、もし入れ子になっていた時など、

予期しないtrを取ってこないためにも指定した方が安全だと思います。


<td><%= link_to 'copy', "#", class: 'copy-user' %></td>

ここがコピーボタンになります。

link_toである必要は特にないのですが、

jQueryのソースの最後に使っているfalseの説明のためこれにしました。

copy-userと言うクラスをクリックのセレクターにします。


<script>
  users.copy();
</script>

jQueryの呼び出しです。


CoffeeScript

では本題のjQueryの部分です。

class UsersController
  .
  .
  .
this.users = new UsersController

まず最初と最後のこの記述ですが、

このように書くと、HTMLの最後に書いたような記述で

メソッドを指定して呼び出すことができます。

仕組みについては現在勉強中です。すみません...

ちゃんと理解したらまた記事に書きます。


$(.copy-user).on 'click', () ->
    currentRow = $(@).parents('.copy-row')

まずはリンクをクリックした時に、

そのリンク(またはボタン等)の親の行を持ってきます。


currentRow.clone(true).innsertAfter(currentRow)

ここがキモです。

まずcurrentRow(コピー対象の行)をclone(true)でコピーします。

引数のtrueで対象のイベントや変数もコピーしてくれます。


ちなみに(true, false)と第2引数をとることもでき、

この場合は子要素のイベントはコピーされません。

こちらを参考にさせていただきました。

jQuery リファレンス:clone


次にinnsertAfter(currentRow)でオリジナルの直下に挿入しています。

.cloneはただ要素の中身諸々をコピーするだけですので、

このように必ずどこかに表示してあげないと画面には反映されません。


なお、もしコピーする行に固有のidとかが付いていた場合、

それも一緒にコピーしてしまって予期しない動作が起こったりしますので、

その場合はそれらを削除する必要があります。

(私の場合はid番号が付いていてdeleteでオリジナルも消えました...)

コピーの動きについては以上です。


補足

コピーの話とは関係ありませんが、最後にあるfalseについてです。

これは該当要素の本来の動きを打ち消してくれるようです。


今回で言えばクリックの対象をlink_toにしていました。

falseなしだとクリックした時に、一瞬行が表示されて、そして消える。

というような不可解な挙動をしたりします。

これはクリックイベントの処理の後にlink本来の動きをしたために起こることです。

この動きを打ち消すことで消えることなく無事表示されます。


まとめ

要素をコピーして表示するというのは結構見かける機能な気がします。

今回はただ単に一覧の行をコピーして入れただけですが、

実際には複数のデータを一括で編集するフォームに実装しました。

覚えておけばまたどこかで使えそうです。