Infienity

Infienity provides infinity scroll, combined with sort and search via web-socket connection. Since infinity scroll requires continuous calls to request new parts of the data, requesting new data via a permanent web-socket connection should be a cleaner approach than using traditional AJAX calls.

This gem is dependent on Fie, a gem that makes DOM manipulations through web sockets possible.

Installation

Add this line to your application's Gemfile:

gem 'infienity'
gem 'fie' # dependency, use your preferred version

And then execute:

$ bundle

Or install it yourself as:

$ gem install infienity

Add Infienity's javascript in your project, by adding the following lines into app/assets/javascripts/application.js:

# just before require_tree
//= require fie
//= require infienity

As Infienity is dependent on Fie, you will have to follow the regular Fie setup, which also includes setting up Redis and replacing yield in your main layout.

Usage

For both infinity scroll, searching and sorting you will need to perform the following steps:

Add the following line in the model you want to perform the actions on:

extend Infienity::Model

Create a commander for your model (for front-end manipulation). The commander should be correspondent to the controller of your model (path: app/commanders/[name]_commander).

class UserCommander < Fie::Commander
  extend Infienity::Commander
  commander_assigns :users # model name in this format
end

In your controller method, you will need to assign some variables, which will hold the state. you must declare all of them in order for the infinity scroll to work:

@index = 0
@per_page = 5 # or omit if you want the default: 10

Pagination

In your controller method, perform the pagination of the infinity scroll like so:

@users = User.paginate

In your view, wrap the dataset in a div or span, with the following class and custom attribute. infienity-model should include your model name, in plural. Example:

<div class="paginate" infienity-model="users">
    <% @users.each do |u| %>
        Name: <%= u.full_name %> <br/>
        Username: <%= u.username %>
    <% end %>
</span>

In your controller method, add the following variables, in order to hold the state:

@search_attribute = 'username'
@search_string = ''

In your view, you can use this predefined layout:

<%= render template: 'layouts/search', locals: { assign: "users", search_string: @search_string } %>

Or use html in this manner:

<input type="text" name="search_string" value="<%= @search_string %>" fie-keyup="filter_users" > </input>

Note: be careful to put the correct assign for fie-keyup attribute

Sort

In your controller method, add the following variables, in order to hold the state:

@sorting_dropdown_options =
    {
    "Username (A-Z)" => [:username, :asc],
    "Username (Z-A)" => [:username, :desc],
    "Date (Asc)" => [:created_at, :asc],
    "Date (Desc)" => [:created_at, :desc]
    }
@selected_dropdown_option = "Username (A-Z)"
  • The keys in the @sorting_dropdown_options are the values the user is going to see.
  • The first value in @sorting_dropdown_options is the model attruibute, and the second is always :asc or :desc.
  • The @selected_dropdown_option must correspond to one of the keys stated in @sorting_dropdown_options

If you use a custom dropdown using <li> elements, you can use this template:

<%= render
  template: 'layouts/sort',
  locals:
    {
      dropdown_options: @sorting_dropdown_options,
      current_option: @selected_dropdown_option,
      assign: "users"
    }
%>

Or for a basic <select> dropdown:

<%= render
  template: 'layouts/sort_select',
  locals: {
    dropdown_options: @sorting_dropdown_options,
    current_option: @selected_dropdown_option,
    assign: "users"
  }
%>

Or use html in this manner:

<div class="dropdown">
    <button type="button" data-toggle="dropdown"> <%= @selected_dropdown_option %>
      <span class="caret"></span>
    </button>
    <ul class="dropdown-menu">
        <% @selected_dropdown_option.each do |key,val| %>
            <li fie-click="sort_users" fie-parameters= "<%= { sort: {key => val} }.to_json %>"> <%= key %> </li>
        <% end %>
    </ul>
</div>

Note: be careful to put the correct assign for fie-click attribute

Template options

To style the html in the templates, add the options hash inside the locals hash, in this manner:

<%= render
  template: 'layouts/sort',
  locals:
    {
      dropdown_options: @sorting_dropdown_options,
      current_option: @selected_dropdown_option,
      assign: "users",
      options: { class: "btn btn-primary dropdown-toggle" }
    }
%>

Supported options:

  • :id
  • :class
  • :name (except for search)

Development

Your first step is to run npm install within the root folder in order to install the relevant NodeJS packages.

To work on the JavaScript, begin by running npm run build. This will start a watcher that will automatically transpile your ES6 within the ib/javascripts folder into a bundle within vendor/javascripts/infienity.js using webpacker.

The Ruby files can be found within lib/infienity and their development is the same as in any other gem.

Please add tests if you add new features or resolve bugs.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/ioanabob/infienity. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.

License

The gem is available as open source under the terms of the MIT License.

Code of Conduct

Everyone interacting in the Infienity project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.