【问题标题】:How to get the right position with Sortable.js, acts_as_list and Stimulus for nested_attributes如何使用 Sortable.js、acts_as_list 和 Stimulus 获得嵌套属性的正确位置
【发布时间】:2020-11-28 10:58:21
【问题描述】:

我正在尝试使用nested_attributes 实现“拖放排序列表”(https://gorails.com/episodes/rails-drag-and-drop-sortable)。

很遗憾,我弄错了:position。即使总共应该只有三个位置,它也会从 2 跳到 5 到 7。

我认为问题在于隐藏的输入标签也被计算在内。如果这是主要问题,有什么办法可以解决这个问题?

// config/routes.rb

  resources :recipes, except: :index do
    resources :steps do
      resource :step_position, only: :update
    end
  end

// app/views/recipes/_form.html.erb

<div data-controller="sortable" data-sortable-url="/recipes/:recipe_id/steps/:id/step_position">
  <%= f.fields_for :steps, @recipe.steps.order(position: :asc) do |step| %>
    <div data-id="<%= step.object.id %>">
      <%= step.text_area :description %>
    </div>
  <% end %>
</div>
// app/javascript/controllers/sortable_controller.js

import { Controller } from "stimulus";
import Rails from "@rails/ujs";
import { Sortable } from "sortablejs";

export default class extends Controller {
  connect() {
    this.sortable = Sortable.create(this.element, {
      onEnd: this.end.bind(this),
    });
  }

  end(event) {
    let id = event.item.dataset.id;
    let data = new FormData();
    data.append("position", event.newIndex + 1);
    Rails.ajax({
      url: this.data.get("url").replace(":id", id),
      type: "PATCH",
      data: data,
    });
  }
}
// app/controllers/step_positions_controller.rb

class StepPositionsController < ApplicationController
  def update
    @step = Step.find(params[:step_id])
    authorize @step.recipe

    @step.insert_at(params[:position].to_i)

    head :ok
  end
end

【问题讨论】:

  • 你有没有得到这个工作?我被困在同一个地方,我的排序顺序也在做同样的事情。当我总共只有 3 个时,跳到 7 个。如果是这样,你最终做了什么?
  • @spacerobot,是的,我做到了!刚刚发布了答案。

标签: ruby-on-rails nested-attributes sortablejs acts-as-list stimulusjs


【解决方案1】:

首先看一下传递给服务器的参数。这些看起来好吗?如果没有,那么 javascript 可能是罪魁祸首。

其次,insert_at 在这种情况下并不是完成这项工作的最佳工具。如果您想显式设置位置而不受回调等干扰...我通常在列表中的每个元素上使用where(:id =&gt; id).update_all(:position =&gt; the_position)(前提是您知道您的参数中包含所有元素。

最好的解决方案是让 javascript 向您发送要移动的项目以及您希望它在列表中的位置,然后只需将位置列设置为该值,acts_as_list 将把事情打乱为你。唯一的缺点是来自其他用户的并发更新。如果出现这种情况,您的列表将不同步。

【讨论】:

    【解决方案2】:

    问题是隐藏的输入标签也被计算在内。

    我通过添加&lt;%= f.hidden_field :id %&gt;解决了它

    <!-- app/views/recipes/_form.html.erb -->
    
    <div data-controller="sortable" data-sortable-url="/recipes/:recipe_id/steps/:id/step_position">
      <%= f.fields_for :steps, @recipe.steps.order(position: :asc), include_id: false do |step| %>
        <%= render "step_fields", f: step %>
      <% end %>
    </div>
    
    <!-- app/views/recipes/_step_fields.html.erb -->
    
    <%= content_tag :div, class: "nested-fields", data: { new_record: f.object.new_record?, id: f.object.id } do %>
      <%= f.hidden_field :id %>
      <%= f.text_area :description %>
    
      <small><%= link_to "Delete", "#", data: { action: "click->new-fields#removeField" } %></small>
      <%= f.hidden_field :_destroy %>
    <% end %>
    

    【讨论】:

    • 谢谢!您介意发布您的步进控制器吗?
    • @spacerobot 和上面一样!不必碰它。
    猜你喜欢
    • 2019-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-16
    • 1970-01-01
    • 1970-01-01
    • 2016-03-30
    • 2012-02-02
    相关资源
    最近更新 更多