2

I'm trying use jquery-ui sortable connected lists and persist sorting changes in a Rails app.

enter image description here

  1. Lists have many tasks.
  2. Lists can be sorted among each other - works.
  3. Tasks can be sorted among each other - works.
  4. Tasks can moved between lists - does not work correctly:

Lists/index.html.erb:

<div class="list-sortable connectedSortable" style="cursor: grab;">
  <% @lists.each do |list| %>
    <%= content_tag "div", id: "list-#{list.id}", data: { model_name: list.class.name.underscore, update_url: list_sort_path(list)} do %>
      <%= render 'lists/list_preview', list: list %>
      <div class="task-sortable connectedSortable" style="cursor: grab;">
        <% list.tasks.rank(:row_order).each do |task| %>
          <%= content_tag "div", id: "task-#{task.id}", data: { model_name: task.class.name.underscore, update_url: list_task_sort_path(list, task)} do %>
            <%= render 'tasks/task_preview', task: task %>
          <% end %>
        <% end %>
      </div>
    <% end %>
  <% end %>
</div>

application.js:

require("jquery-ui-dist/jquery-ui");

$(document).on('turbolinks:load', function(){
  $('.list-sortable').sortable({
    cursor: "grabbing",
    //cursorAt: { left: 10 },
    placeholder: "ui-state-highlight",
    update: function(e, ui){
      let item = ui.item;
      let item_data = item.data();
      let params = {_method: 'put'};
      params[item_data.modelName] = { row_order_position: item.index() }
      $.ajax({
        type: 'POST',
        url: item_data.updateUrl,
        dataType: 'json',
        data: params
      });
    },
    stop: function(e, ui){
      console.log("stop called when finishing sort");
    }
  });

  $('.task-sortable').sortable({
    cursor: "grabbing",
    //cursorAt: { left: 10 },
    placeholder: "ui-state-highlight",
    update: function(e, ui){
      let item = ui.item;
      let item_data = item.data();
      let params = {_method: 'put'};
      params[item_data.modelName] = { row_order_position: item.index(), list_id: item.index() };
      $.ajax({
        type: 'POST',
        url: item_data.updateUrl,
        dataType: 'json',
        data: params
      });
    },
    stop: function(e, ui){
      console.log("stop called when finishing sort");
    }
  });

  $( function() {
    $( ".list-sortable, .task-sortable" ).sortable({
      connectWith: ".connectedSortable"
    }).disableSelection();
  } );

});

As I understand, the problem is in this line:

      params[item_data.modelName] = { row_order_position: item.index(), list_id: ??????????? };

I can not figure out how to pass list_id correctly (as the list.id to which the task was dragged)

Github repo: https://github.com/yshmarov/jquery-sortable-rails

Heroku demo: https://jquery-sortable-rails.herokuapp.com

1 Answer 1

1
+50

Try this

<div class="chapter-sortable" style="cursor: grab;">
  <% @lists.each do |list| %>
    <%= content_tag "div", id: "list-#{list.id}", data: { id: list.id, model_name: list.class.name.underscore, update_url: list_sort_path(list)} do %>
      <%= render 'lists/list_preview', list: list %>

      <div class="lesson-sortable" style="cursor: grab; min-height: 10px;">
        <% list.tasks.rank(:row_order).each do |task| %>
          <%= content_tag "div", id: "task-#{task.id}", data: { model_name: task.class.name.underscore, update_url: list_task_sort_path(list, task)} do %>
            <%= render 'tasks/task_preview', task: task %>
          <% end %>
        <% end %>
      </div>
    <% end %>
  <% end %>
</div>

$(document).on('turbolinks:load', function () {
  $('.chapter-sortable').sortable({
    axis        : "y",
    cursor      : "grabbing",
    placeholder : "ui-state-highlight",

    update: function(_, ui){
      let item      = ui.item
      let itemData  = item.data()
      let params    = { _method: 'put' }

      params[itemData.modelName] = { row_order_position: item.index() }

      $.ajax({
        type     : 'POST',
        url      : itemData.updateUrl,
        dataType : 'json',
        data     : params
      })
    },
  })

  $('.lesson-sortable').sortable({
    axis        : "y",
    cursor      : "grabbing",
    placeholder : "ui-state-highlight",
    connectWith : '.lesson-sortable',

    update: function(_, ui){
      if (ui.sender) return

      let item      = ui.item
      let itemData  = item.data()
      let listID    = item.parents('.ui-sortable-handle').eq(0).data().id
      let params    = { _method: 'put' }

      params[itemData.modelName] = { row_order_position: item.index(), list_id: listID }

      $.ajax({
        type     : 'POST',
        url      : itemData.updateUrl,
        dataType : 'json',
        data     : params
      })
    }
  })
})

class ListsController < ApplicationController
  def index
    @lists = List.rank(:row_order)
  end
end
1
  • good point about passing the list.id in the view. The work you did with the JS file is amazing. That's what I yearned for! & I just missed .rank(:row_order) in the controller. Thanks!
    – Yshmarov
    Commented Oct 29, 2020 at 10:23

Not the answer you're looking for? Browse other questions tagged or ask your own question.