Rails Sortable报错:Cannot read properties of undefined (reading 'dataset')
拖拽排序触发TypeError: Cannot read properties of undefined (reading 'dataset')的问题解决
问题概述
实现基于Hotwire的拖拽排序功能时,拖拽完成后抛出错误:
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'dataset')
相关代码如下:
Project模型
acts_as_list scope: :project
_project.html.erb
<div id="projects" data-controller="position"> <%= content_tag :div, data: { sgid: project.to_sgid_param, id: "#{dom_id project}" }, class: 'table-row' do %> <div><%= project.name %></div> <div><%= project.description %></div> <div><%= project.status %></div> <div><%= project.user.email %></div> <div class="flex justify-end"> <%= link_to "View", project_path(project), data: {turbo: false} %> <%= button_to "Delete", project, method: :delete, form: {data: {turbo_confirm: "Are you sure?"}} %> </div> <% end %> </div>
position_controller.js
import { Controller } from "@hotwired/stimulus"; import Sortable from "sortablejs" import { put } from "@rails/request.js" export default class extends Controller { connect() { this.sortable = Sortable.create(this.element, { animation: 150, onEnd: this.updatePosition.bind(this) }) } async updatePosition(event) { const response = await put('/projects', { body: JSON.stringify({ sgid: event.project.dataset.sgid, position: event.newIndex + 1 }) }) if (response.ok) { console.log(event.project.dataset.sgid) } } }
错误原因
核心问题是SortableJS的onEnd事件对象中不存在project属性,你错误地使用了event.project来获取被拖拽的元素。SortableJS的事件对象里,代表被拖拽元素的属性是event.item,而非event.project。当你尝试访问event.project.dataset时,event.project是undefined,自然会抛出读取dataset的错误。
修复方案
将JavaScript代码中所有的event.project替换为event.item,即可正确获取到带有data-sgid属性的拖拽元素。
修改后的position_controller.js
import { Controller } from "@hotwired/stimulus"; import Sortable from "sortablejs" import { put } from "@rails/request.js" export default class extends Controller { connect() { this.sortable = Sortable.create(this.element, { animation: 150, onEnd: this.updatePosition.bind(this) }) } async updatePosition(event) { const draggedItem = event.item; const response = await put('/projects', { body: JSON.stringify({ sgid: draggedItem.dataset.sgid, position: event.newIndex + 1 }) }) if (response.ok) { console.log(draggedItem.dataset.sgid) } } }
额外检查点
- 确认HTML中每个拖拽项(即
content_tag生成的.table-row元素)确实包含data-sgid属性,当前代码中已正确设置。 - 确保后端的
PUT /projects路由能够正确接收并处理sgid和position参数,完成排序更新逻辑。
内容的提问来源于stack exchange,提问作者spacerobot
相关产品推荐
相关产品推荐

