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

Shiny中sortable的rank_list无法在shinyalert/模态框交互

Shiny sortable rank_list在弹窗中无法拖拽的解决方法

问题原因

sortable包的rank_list组件依赖页面加载时执行的JavaScript代码完成拖拽功能初始化。当你把提前生成的rank_list对象放入shinyalert弹窗时,弹窗是动态添加到DOM中的,初始化脚本不会自动针对这些新元素运行,导致拖拽和选中功能失效。而selectInput这类原生Shiny组件会自动处理动态渲染的交互逻辑,因此不受影响。

解决方案

方案1:使用Shiny原生modalDialog替代shinyalert

Shiny原生模态框能自动处理动态添加组件的依赖加载与初始化,只需在触发弹窗时动态创建rank_list即可:

library(shiny)
library(sortable)

labels <- list(
  "one",
  "two",
  "three",
  htmltools::tags$div(htmltools::em("Complex"), " html tag without a name"),
  "five" = htmltools::tags$div(htmltools::em("Complex"), " html tag with name: 'five'")
)

ui <- fluidPage(
  rank_list(
    text = "主页面排序组件",
    labels = labels,
    input_id = "rank_list_main",
    options = sortable_options(multiDrag = TRUE)
  ),
  actionButton("showModal", "打开原生模态框")
)

server <- function(input, output, session) {
  observeEvent(input$showModal, {
    showModal(modalDialog(
      title = "重新排序这些项",
      tagList(
        # 动态创建rank_list,确保初始化脚本正确执行
        rank_list(
          text = "可多选后拖拽分组",
          labels = labels,
          input_id = "rank_list_modal",
          options = sortable_options(multiDrag = TRUE)
        ),
        br(),
        selectInput("modalTextInput", "选择字母", choices = c("a", "b", "C"))
      ),
      easyClose = TRUE,
      footer = modalButton("关闭")
    ))
  })
  
  # 监听模态框排序结果
  observeEvent(input$rank_list_modal, {
    print("模态框排序结果:")
    print(input$rank_list_modal)
  })
  
  # 监听主页面排序结果
  observeEvent(input$rank_list_main, {
    print("主页面排序结果:")
    print(input$rank_list_main)
  })
}

shinyApp(ui, server)

方案2:在shinyalert弹窗显示后手动初始化sortable

若坚持使用shinyalert,可通过callbackJS参数在弹窗显示后执行JavaScript代码,手动初始化拖拽功能:

library(shiny)
library(sortable)
library(shinyalert)

labels <- list(
  "one",
  "two",
  "three",
  htmltools::tags$div(htmltools::em("Complex"), " html tag without a name"),
  "five" = htmltools::tags$div(htmltools::em("Complex"), " html tag with name: 'five'")
)

rank_list_alert <- rank_list(
  text = "可多选后拖拽分组",
  labels = labels,
  input_id = "rank_list_alert",
  options = sortable_options(multiDrag = TRUE)
)

ui <- fluidPage(
  rank_list(
    text = "主页面排序组件",
    labels = labels,
    input_id = "rank_list_main",
    options = sortable_options(multiDrag = TRUE)
  ),
  actionButton("showAlert", "打开shinyalert弹窗")
)

server <- function(input, output, session) {
  observeEvent(input$showAlert, {
    shinyalert(
      title = "重新排序这些项",
      html = TRUE,
      closeOnClickOutside = TRUE,
      showConfirmButton = TRUE,
      text = tagList(
        rank_list_alert,
        br(),
        selectInput("alertTextInput", "选择字母", choices = c("a", "b", "C"))
      ),
      # 弹窗显示后执行初始化代码
      callbackJS = 'function() {
        const sortableContainer = document.querySelector(".shinyalert .rank-list-container");
        if (sortableContainer) {
          Sortable.create(sortableContainer, {
            multiDrag: true,
            // 同步排序结果到Shiny输入
            onEnd: function(evt) {
              const items = Array.from(sortableContainer.children).map(el => {
                return el.getAttribute("data-value") || el.textContent.trim();
              });
              Shiny.setInputValue("rank_list_alert", items);
            }
          });
        }
      }'
    )
  })
  
  # 监听弹窗排序结果
  observeEvent(input$rank_list_alert, {
    print("弹窗排序结果:")
    print(input$rank_list_alert)
  })
}

shinyApp(ui, server)

注意事项

  • 方案1更简洁,推荐优先使用,Shiny原生模态框会自动处理组件的依赖与生命周期。
  • 方案2需要手动匹配R端的sortable_options配置(如multiDrag),并确保排序结果同步到Shiny输入。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 12:19:59