Posted at

【Rails5】Ajaxでビューに要素を追加する方法と、それに対してjQueryでイベントハンドラを設定する方法


概要

以下の項目について、Rails初心者の私が躓いた部分がいくつかあったので、

備忘録を兼ねて、シンプルなコードを例に知見を共有します。


  • Rails5系でAjaxを使用する方法

  • 動的に生成したDOM要素に対してjQueryでイベントハンドラを設定する方法


目標とする動作

824cb2b7a55ed598b5cb1363455f3dc6.gif


Rails5系でAjaxを使用する方法

先程のgifでいうところの、各ニュースタイトルの横にある『あとで読む』ボタン押下後、

『あとで読むリスト』にその項目をAjaxで追加する部分について解説します。


ビュー

こちらが、ビューのソースコードです。

(erbはQiita側のシンタックスハイライトが上手く効かなかった:sob:)


home.html.erb

    #読売新聞の記事一覧を表示するテーブル。

        #@all_newsには最新のニュースに関する全てのレコードが入っている。
         <table class="latest_news_table">
<thead>
<tr>
<th>タイトル</th>
<th></th>
</tr>
</thead>
<tbody>
<% @all_news.each do |news| %>
<tr>
<td><%= link_to news.title, news.link %></td>
#あとで読むボタンには、各ニュースに対応したidが付与されている
<td><span class="btn btnAtode" id=<%= news.id %>>あとで読む</span></td>
</tr>
<% end %>
</tbody>
</table>

#あとで読む記事を表示するテーブル。
#all_atodesにはあとで読む予定のニュース記事に関する全てのレコードが入っている。
        <table class="atode_news_table">
<thead>
<tr>
<th>タイトル</th>
<th></th>
</tr>
</thead>
<tbody>
<% @all_atodes.each do |atode| %>
<tr>
<td><%= link_to atode.title, atode.link %></td>
<td><span class="btn btnDokuryo" id=<%= atode.id %> method: :delete>読了</span></td>
</tr>
<% end %>
</tbody>
</table>



Ajax処理を行うjsファイル

app/assets/javascripts配下に作成しました。


Ajax.js

$(function () {

//あとで読むボタンに対するイベントハンドラ
$(".btnAtode").click(function() {
//ボタンのidを取得し、後述するatodeアクションに渡す。
return $.ajax({
url: 'ajax/atode',//routes.rbの記述で、このurlとコントローラーのアクションを対応付ける
type: 'post',
data: { set_id: $(this).attr('id') },//アクションに渡したいデータ
dataType: 'json',
async: true,
//コントローラーから無事にjsonが帰ってきた際の動作
}).done(function(response) {
//atodeアクション終了後の動作。あとで読むリストに項目を追加
//response[0]にニュースのタイトル、[1]にurl、[2]にidが格納されている
$(".atode_news_table").append(
"<tr><td><a href="
                    + response[1] + ">" + response[0]
+ "</a></td><td><span class='btn btnDokuryo' id="
+ response[2] + " method: :delete>読了</span></td></tr>"
)
//コントローラーからjsonが帰ってこなかった時の動作
}).fail(function() {
     alert("失敗しました");
});
});
});


コントローラー

あとで読むボタンのクリックに対応したアクションです。


home_controller.rb

  def atode

        #あとで読むボタンが押された場合、ボタンに付与されたidをもとにNewsテーブルからニュースを取得
@cheked_news = News.find(params[:set_id])
#取得したニュースと同じ内容をAtodeテーブルに記録
@atode_news = Atode.create(source: @cheked_news.source, title: @cheked_news.title,
link: @cheked_news.link, checked: true)
#各値をjsonに格納して、ajax.jsに返却 ajax.jsではresponse[0]〜[2]として扱われる
render json: [@cheked_news.title, @cheked_news.link, @atode_news.id]
end


動的に生成したDOM要素に対して、jQueryでイベントハンドラを設定する方法

先程のgifでいうところの、Ajaxで『あとで読むリスト』に追加された項目の『読了』ボタンを押すと

記事が消えていく動作について解説します。

方法としてはajax.jsの『あとで読むリスト』に各値を追加

イベントハンドラを設定するだけです。

以下、先程のajas.jsに一部加筆


Ajax.js

//略

}).done(function(response) {
$("#atode-table").append(
"<tr>" +
"<td><a href=" + response[1] + ">" + response[0]
+ "</a></td>"
+ "<td><span class='btn btn-info btn-sm btnDokuryo' id="
+ response[2] + " method: :delete>読了</span></td></tr>"
)
//以下加筆箇所
            //読了ボタンに対するイベントハンドラ
$(".btnDokuryo").click(function(){
let set_id = Number( $(this).attr('id') )
return $.ajax({
url: 'ajax/done',
type: 'delete',
data: { set_id },
dataType: 'json',
async: true,
//response[0]に削除したい項目のidが格納されている
}).done(function(response) {
//あとで読むリストの項目を削除
var done_article = $("#" + response[0]).closest("tr").remove();
$(done_article).remove();
}).fail(function() {
});
})
//略



まとめ

Ajaxの使い方については、シンプルなコードを載せてみました。

必要箇所をコピペしてお使い下さい。

また、Ajaxで動的に生成したDOM要素に対しては、

その要素を追加にイベントハンドラを設定する所がポイントです。

私は別のjsファイルを作成し、そちらでイベントハンドラを設定していましたが、

Ajaxで追加した項目についてはclickイベントが拾えず悩んでしまいました...。

同様の悩みを抱えている方の助けになれば幸いです。