Components

Sortable

A Stimulus controller to reorder lists with drag-and-drop.


Installation

  1. Install the package

    Terminal
    $ yarn add @stimulus-components/sortable sortablejs @rails/request.js
    
  2. Register the controller in your application

    app/javascript/controllers/index.js
    import { Application } from '@hotwired/stimulus'
    import Sortable from '@stimulus-components/sortable'
    
    const application = Application.start()
    application.register('sortable', Sortable)
    

This component is based on the SortableJS.

Example

Sortable

  • Pet the cat
  • Get the groceries

With custom handler

  • Pet the cat
  • Get the groceries

Usage

app/models/todo.rb
class Todo < ApplicationRecord
  acts_as_list # Or with a custom position system.
end
app/controllers/todos_controller.rb
class TodosController < ApplicationController
  def update
    # Do what you want with todo_params.
  end

  private

  def todo_params
    params.require(:todo).permit(:position)
  end
end

In your views:

Basic usage

app/views/index.html
<ul data-controller="sortable" data-sortable-animation-value="150">
  <li>Pet the cat</li>
  <li>Get the groceries</li>
</ul>

With custom handler

app/views/index.html
<ul data-controller="sortable" data-sortable-handle-value=".handle">
  <li>
    <svg class="handle"></svg>
    Pet the cat
  </li>

  <li>
    <svg class="handle"></svg>
    Get the groceries
  </li>
</ul>

With AJAX call

If you're using @rails/request.js in your application, you can add an url as data-attribute on every items to perform an AJAX call to update the new position automatically on drop.

app/views/index.html
<ul data-controller="sortable" data-sortable-resource-name-value="todo">
  <%= @todos.each do |todo| %>
    <!-- <li data-sortable-update-url="/todos/1">Pet the cat</li> -->
    <li data-sortable-update-url="<%= todo_path(todo) %>"><%= todo.description %></li>
  <% end %>
</ul>

By default, position will be used as param in a PATCH request. You can change it with the data-sortable-param-name-value attribute.

If you use data-sortable-resource-name-value, the name will be used. For instance, todo[position].

Configuration

AttributeDefaultDescriptionOptional
data-sortable-resource-name-valueundefinedName of the resource to use as AJAX param.
data-sortable-param-name-valuepositionName of the attribute to use as AJAX param.
data-sortable-response-kind-valuehtmlThe response kind you want for @rails/request.js.
data-sortable-animation-value150Animation speed moving items when sorting in milliseconds. 0 to disable.
data-sortable-handle-valueundefinedDrag handle selector within list items.

Extending Controller

You can use inheritance to extend the functionality of any Stimulus component:

app/javascript/controllers/sortable_controller.js
import Sortable from "stimulus-sortable"

export default class extends Sortable {
  connect() {
    super.connect()
    console.log("Do what you want here.")

    // The sortable.js instance.
    this.sortable

    // Your options
    this.options

    // Your default options
    this.defaultOptions
  }

  // You can override the `onUpdate` method here.
  onUpdate(event) {
    super.onUpdate(event)
  }

  // You can set default options in this getter for all sortable elements.
  get defaultOptions() {
    return {
      animation: 500,
    }
  }
}

This controller will automatically have access to targets defined in the parent class.

If you override the connect, disconnect or any other methods from the parent, you'll want to call super.method() to make sure the parent functionality is executed.