0
0

More than 3 years have passed since last update.

【jQuery】Ajaxで追加した要素へ正しくイベントセットする方法

Posted at

概要

自作ポートフォリオの買い物メモアプリで、Ajaxを用いてメモの投稿機能を非同期処理に書き換えたところ、bootstrap4(modal) & jQueryで実装していた、投稿に対するコメント投稿機能が動かなくなる不具合が発生しハマったため、備忘録のために投稿しました。

結論

私の場合、modalに値を渡す処理を書いていたjQueryのコードを修正したことで改善出来ました。
Ajaxで実装した動的な要素(投稿)に対して、適切なイベントセットが出来ていなかったことが原因です。

app/assets/javascripts/comment_modal.js
変更前
$(".js_comment_btn").on("click",function() {
$("#comment_id").val(this.value);
});

変更後
$(document).on("click",".js_count_btn",function() {
$("#comment_id").val(this.value);
});

app/views/notes/index.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title><%= full_title(yield(:title)) %></title>
     <%= csrf_meta_tags %>
     <%= stylesheet_link_tag    "application", media: "all", "data-turbolinks-track": "reload" %>
     <%= javascript_include_tag "application", "data-turbolinks-track": "reload" %>
  </head>

  <body>

    <!-- 以下、投稿用の部分テンプレート -->
    <div id="index">
     <%= render "shared/my_content", note: @own_notes %>
    </div>

    <!-- 以下、コメント投稿用のモーダル -->
    <%= render "shared/note_modal" %>

    <%= form_with model: @note do |f| %>
      <%= f.text_field :content,id:"note_create_form",class:"form-control" , placeholder: "商品名を入力" %>
      <%= f.submit "投稿", class: "btn btn-light form-btn" %></li>
    <% end %>            
  <body>
</html>
app/views/notes/_my_content.html.erb
  <% note.each do |note| %>
    <ul>
      <li class="note_content">
        <%= note.content %>
        <button type="button" class="btn js_comment_btn" data-toggle="modal"
         data-target="#comment_Modal" value="<%= note.id %>" id="js_count">
        <i class="fa fa-sort" aria-hidden="true"></i></button>
      </li>
    </ul>
  <% end %>
app/controllers/notes_controller.rb
  class NotesController < ApplicationController

    def create
      note = current_user.notes.build(note_params)
        if note.save
          @own_notes = current_user.notes.includes(comments: :user)
          render "create.js.erb"
        else
          flash[:danger] = "投稿に失敗しました"
          render "notes/index"
        end
    end
  end
app/views/notes/create.js.erb
$("#index").html("<%= j(render "shared/my_content", { note: @own_notes }) %>")

具体的解説

エラー内容

①Ajax形式でPOSTリクエストを送り、notes_controllerで投稿オブジェクトを作成。
②jsファイル(create.js)にレンダリングし部分テンプレートの中身を更新
③作成されたオブジェクトのbuttonでモーダルを起動
④モーダルにテキスト入力してPOSTリクエストを送るとエラーが出る
(ActiveRecord::RecordNotFound (Couldn't find Note with 'id'=):)
⑤ページをリロードし再度、③④を実行すると動く

devtoolで調べた結果、modalに投稿のIDを渡す処理が走っていませんでした。
その後原因究明してわかったのは

部分的にしか更新しないAjaxだと、DOM要素の指定に工夫が必要だということ

今回の場合、
jsファイルで部分的にページの更新

modalを呼び出すbutton要素部分(部分テンプレート内)とmodal本体(部分テンプレート外)の間で
整合性が取れなくなり④のエラーが発生

ページ全体のリロードによりDOMが再構築されると問題なく動くようになる

そのため、下記のように親要素の下のクラスという指定をしてあげることで
改善することが出来ました。

app/assets/javascripts/comment_modal.js
$(document).on("click",".js_count_btn",function() {
$("#comment_id").val(this.value);
});

実行環境

・Ruby v2.7.0
・Ruby on Rails v5.1.7
・jQuery-rails v4.4.0
・bootstrap v4.3.1

0
0
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
0
0