Ajaxを使った要素の追加と自動更新


概要

Jqueryで要素の追加と自動更新

開発環境

2019/10/16

macOs 10.14.6
ruby 2.5.1p57
Rails 5.0.7.2
mysql Ver 14.14 Distrib 5.6.43

gemfile
source 'https://rubygems.org'

git_source(:github) do |repo_name|
  repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/")
  "https://github.com/#{repo_name}.git"
end


# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 5.0.7', '>= 5.0.7.2'
gem 'mysql2', '>= 0.3.18', '< 0.6.0'
gem 'puma', '~> 3.0'
gem 'sass-rails', '~> 5.0'
gem 'uglifier', '>= 1.3.0'
gem 'coffee-rails', '~> 4.2'
gem 'jquery-rails'
gem 'turbolinks', '~> 5'
gem 'jbuilder', '~> 2.5'
gem 'devise'
gem 'rails-i18n', '~> 5.1'
gem 'carrierwave'
gem 'mini_magick'
gem 'pry-rails'

group :development, :test do
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'byebug', platform: :mri
  gem 'spring'
  gem 'compass-rails'
  gem 'sprockets'
  gem 'kaminari'
  gem 'rspec-rails'
  gem 'factory_bot_rails'
  gem 'rails-controller-testing'
  gem 'faker'
  gem 'capybara'
end

group :development do
  # Access an IRB console on exception pages or by using <%= console %> anywhere in the code.
  gem 'web-console', '>= 3.3.0'
  gem 'listen', '~> 3.0.5'
  # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
  gem 'spring'
  gem 'spring-watcher-listen', '~> 2.0.0'
  gem 'haml-rails', ">= 1.0", '<= 2.0.1'
  gem "font-awesome-rails"
end

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

要素を追加・削除するためのコード

message.js
$(document).on("turbolinks:load", function() {

    var buildMessageHTML = function(message) {
      var content = message.content                                    //jbuilderの値から追加する要素を宣言
        ? `<p class="lower-message__content">${message.content}</p>`   //リテラルテンプレート記法で+などの演算子を減らし、変数も使えるようにしている
        : ``;                                                          //三項演算子を使いデータがなかった場合は空文字をいれる
      var image = message.image.url
        ? `<img src="${message.image.url}"class="lower-message__image">`
        : ``;
      var html = `<div class="message" data-id=${message.id}>         
                    <div class="upper-message"> 
                      <div class="upper-message__user-name"> 
                        ${message.user_name} 
                      </div> 
                      <div class="upper-message__date"> 
                        ${message.created_at} 
                      </div> 
                    </div> 
                    <div class="lower-message"> 
                      ${content}
                      ${image}
                    </div>
                  </div>`;
      return html;                                                 //jsではrubyと違ってreturnで返り値を示さないといけない
    };

    var reloadMessages = function() {
      last_message_id = $(".message:last").data("id");            //:lastで指定してる要素の最後を取得          
      group_id = $(".chat-main").data("id");                      //カスタムデータ属性からdataメソッドを使ってpathに必要なidを取得
      $.ajax({                         
        url: `/groups/${group_id}/api/messages`,
        type: "get",
        dataType: "json",
        data: { id: last_message_id }
      })
        .done(function(messages) {
          var insertHTML = "";
          messages.forEach(function(message) {
            insertHTML = buildMessageHTML(message                 //要素を追加するメソッドを呼んでforEachで取得したデータの分だけ繰り返す
          });
          $(".messages").append(insertHTML);                     //appendで指定したクラスの下に要素を追加
          $(".messages").animate({ scrollTop: $(".messages")[0].scrollHeight }); //メッセージ画面を下までスクロール//animatメソッドで引数によって、スクロールのコントロールできる
        })
        .fail(function() {
          alert("更新に失敗しました");
        });
    };

   if ($(".chat-main").length) {
    autoReload = setInterval(reloadMessages, 5000); //5秒毎にメソッドを発火
   } else {
    clearInterval(autoReload);                   //メソッドの繰り返しをストップ
   }
});

説明

細かい説明はコメントでしています

今回はクラス名の要素の有無で発火を分岐させていたがURlでも指定できる

特定のページでのみjsを発火させる方法

removeメソッドを使えば要素の削除もできます。
jsで追加した動的要素に対してイベントを発火させたいときは 下記を使うらしいです!!
$(document).on("turbolinks:load", function() { 

参考ページ

Rails + jQueryでインクリメンタルサーチ(基礎)
RubyOnRails/インクリメンタルサーチの実装

最後に

少しでも学習の助けになればいいなと思います
ミスや間違いがあった場合はすみません!!