#概要
以下の項目について、Rails初心者の私が躓いた部分がいくつかあったので、
備忘録を兼ねて、シンプルなコードを例に知見を共有します。
- Rails5系でAjaxを使用する方法
- 動的に生成したDOM要素に対してjQueryでイベントハンドラを設定する方法
#Rails5系でAjaxを使用する方法
先程のgifでいうところの、各ニュースタイトルの横にある『あとで読む』ボタン押下後、
『あとで読むリスト』にその項目をAjaxで追加する部分について解説します。
##ビュー
こちらが、ビューのソースコードです。
(erbはQiita側のシンタックスハイライトが上手く効かなかった)
#読売新聞の記事一覧を表示するテーブル。
#@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配下に作成しました。
$(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("失敗しました");
});
});
});
##コントローラー
あとで読むボタンのクリックに対応したアクションです。
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に一部加筆
//略
}).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イベントが拾えず悩んでしまいました...。
同様の悩みを抱えている方の助けになれば幸いです。