Кнопка «Load More» с использованием Ajax и jQuery и пагинация страниц в Ruby on Rails

в 11:45, , рубрики: ajax, button, coffeescript, jquery, ruby on rails, метки: , , , ,

Сам я только новичок в изучении RoR, но при разработке собственного проекта возникло желание вместо классической пагинации с помощью гема will_paginate сделать ее более удобной при помощи javascript. Это должна быть классическая кнопка, при нажатии на которую загружаются следующие n-записей. Решение проблемы на русском языке я не нашел, на английском есть, но я нашел только громоздкие и неудобные варианты. Как говорится, хочешь сделать что-то хорошо — сделай это сам. Вот что получилось.

Разбиение на страницы будем производить с помощью все того же гема will_paginate, также мы будем его использовать если javascript у пользователя отключен.

Итак сначала устанавливаем гем:

gem 'will_paginate'
bundle install


Затем начинаем с контроллера. В моем случае это будет разбиение на страницы списка пользователей. Соответственно это действие 'index', которое должно отвечать на javascript (:js) запрос:

respond_to :html, :xml, :json, :js

 def index
    @users = User.paginate(page: @@page)
    respond_with @users
 end

Переменная класса

@@page

используется в качестве счетчика. Чуть позже мы к ней вернемся.

Далее идем во вьюху index.html.erb и добавляем пагинацию:

<h1>All users</h1>

<ul class="users">
    <%= render @users %>
</ul>

<div id="without_button">
<%= will_paginate @users %>
</div>


<% if @users.next_page %>
<div id="load_more_users">
    <%= button_to 'More users', {action: "index", new_req: true }, method: :get, remote: true, class: "btn btn-primary btn-large" %> 
</div>
<% end %>

Поясню несколько моментов. Здесь у нас два блока. Первый c id «without_button» добавляет стандартную строку гема по разбиению страниц. Ее мы будем использовать когда javascript отключен:

image

Второй блок включает кнопку. Она будет показана только если количество юзеров достаточно для разбения на записи. По умолчанию для will_paginate это 30 записей. Соответственно если их 30 и меньше, метод next_page возвратит nil и блок загружен не будет. Если javascript отключен, кнопки быть не должно. Соответственно прописываем в css:

#load_more_users {
  display: none;
}

Кнопка передает управление нашему действию c хэшем params[:new_req], значение которого мы уставливаем в true. Объяснение будет дальше.

Итак теперь мы должны понять, что нам нужно загрузить следующие записи. Причем счетчик должен быть равным 1 (первая страница) при загрузке или обновлении страницы. Здесь нам помогает params[:new_req], пока не нажата кнопка он равен nil, если же равен true, то увеличиваем значение счетчика на 1. Еще один момент, если javascript отключен, то пагинация будет происходить через хэш params[:page]. А значит его значение мы и будем присваивать cчетчику. Надеюсь доступно объяснил. Итак мы создаем следующим метод:

private

 def up_page 
      if params[:new_req]
        @@page+=1
      elsif params[:page]
        @@page=params[:page]
      else
        @@page=1
      end
  end

Переменная класса используется потому, что переменная экземпляра создается заново каждый раз при новом обращении к действию.

Метод должен выполняться перед действием index:

 before_action :up_page, only: :index

Теперь самое интересное. Переходим к СoffeeScript. Добавлем следующий код в файл app/assets/javascripts/users.js.coffee

 $('#with_button').hide()
      $('#load_more_users').show()
      $('#load_more_users form').after('<button class="btn btn-primary btn-large btn-clone disabled" style="display: none;">More users</button>')
      $('#load_more_users').click ->
      	$('#load_more_users').find('form').hide().siblings('button').show()

Первая строчка скрывает классическую пагинацию, вторая показывает кнопку. Затем после нашей кнопки мы добавляем вторую кнопку-клона с затемненным фоном, которая будет показана вместо первой кнопки при клике на нее. В принципе кнопка-клон здесь не обязательна. Вместо нее можно показывать строку загрузки или любую другую картинку/гифку.

Осталось подключить Ajax. Добавляем следующий код в index.js.erb:

$('.users').append('<%= j render @users %>').siblings('#load_more_users').find("button").hide().siblings('form').show();

<% unless @users.next_page %>
    $('#load_more_users').remove();
<% end %>

После загрузки следующих n-записей пользователей мы скрываем кнопку-клона и снова показываем нашу форму с первой кнопкой. Кнопку-клона мы создаем для того, чтобы предотвратить повторное нажатие на кнопку, пока не загрузятся записи. Ну и удаляем нашу кнопку, когда все записи из нашего массива ActiveRecord::Relation уже показаны.

Вот и все. Надеюсь эта информация будет кому-нибудь полезна.

Автор: dnom

Источник

* - обязательные к заполнению поля