You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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)
    }
  }
}

额外检查点

  1. 确认HTML中每个拖拽项(即content_tag生成的.table-row元素)确实包含data-sgid属性,当前代码中已正确设置。
  2. 确保后端的PUT /projects路由能够正确接收并处理sgid和position参数,完成排序更新逻辑。

内容的提问来源于stack exchange,提问作者spacerobot

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 03:01:21