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

R Shiny多选项拖拽移动功能实现求助:扩展shinyjqui现有方案

Multi-Select Support for shinyjqui orderInput

Great question! I’ve tackled this exact multi-selection + drag-and-drop scenario with shinyjqui before, and there are a couple of ways to make it work. Let me walk you through a practical solution that adds checkbox-based multi-selection with batch movement, while keeping the original drag-and-drop functionality intact.

Approach Overview

The default orderInput doesn’t support multi-select drag out of the box, but we can extend it by:

  • Adding checkboxes to each item in the containers
  • Using reactive values to track items in each list
  • Adding buttons to trigger batch movement of selected items
  • Keeping the original drag-and-drop functionality for single-item interactions

Modified Code Implementation

library(shiny)
library(shinyjqui)

ui <- fluidPage(
  fluidRow(
    column(
      width = 12,
      uiOutput("OrderInputRender")
    )
  )
)

server<- function(input, output, session){
  # Reactive values to track items in each container (persists state)
  rv <- reactiveValues(
    available = colnames(mtcars),
    selected = character(0)
  )
  
  output$OrderInputRender <- renderUI({
    fluidRow(
      column(width = 5,
             # Available columns with checkboxes for multi-selection
             orderInput(
               "All_Columns",
               width = "100%",
               label = "Available columns (check to select)",
               items = lapply(rv$available, function(col) {
                 tags$div(
                   class = "item",
                   tags$input(type = "checkbox", class = "item-checkbox", value = col),
                   tags$span(col)
                 )
               }),
               style="margin:5px 0 0 0%; overflow: auto; background-color:#DCDCDC; border: 0; padding: 10px; height:360px;",
               connect = "Channel_Column"
             ),
             # Button to batch move selected items to the right
             actionButton("move_right", "Move Selected →", class = "btn-primary btn-block mt-2")
      ),
      column(width = 5,
             # Selected columns with checkboxes
             orderInput(
               "Channel_Column",
               width = "100%",
               label = "Selected columns (check to select)",
               items = lapply(rv$selected, function(col) {
                 tags$div(
                   class = "item",
                   tags$input(type = "checkbox", class = "item-checkbox", value = col),
                   tags$span(col)
                 )
               }),
               style="margin:5px 0 0 0%; overflow: auto; background-color:#DCDCDC; border: 0; padding: 10px; height:360px;",
               connect = "All_Columns"
             ),
             # Button to batch move selected items to the left
             actionButton("move_left", "← Move Selected", class = "btn-primary btn-block mt-2")
      ),
      column(width = 2,
             # Helper display to show current selections
             h4("Selected Items"),
             verbatimTextOutput("current_selections")
      )
    )
  })
  
  # JavaScript to fetch checked checkbox values when buttons are clicked
  tags$script(HTML("
    // Listen for message from Shiny to get checked items
    Shiny.addCustomMessageHandler('get_checked', function(data) {
      var checkedValues = [];
      $(data.container + ' .item-checkbox:checked').each(function() {
        checkedValues.push($(this).val());
      });
      // Send checked values back to Shiny as input
      Shiny.setInputValue('checked_items', checkedValues);
    });
  "))
  
  # Helper function to retrieve checked items
  get_selected_items <- function() {
    session$sendCustomMessage("get_checked", list(container = "#All_Columns, #Channel_Column"))
    isolate(input$checked_items)
  }
  
  # Handle moving selected items from available to selected
  observeEvent(input$move_right, {
    selected <- get_selected_items()
    # Filter to only items in the available list
    to_move <- intersect(selected, rv$available)
    
    if(length(to_move) > 0){
      rv$available <- setdiff(rv$available, to_move)
      rv$selected <- c(rv$selected, to_move)
      # Uncheck checkboxes after moving
      session$sendCustomMessage("uncheck_all", list())
    }
  })
  
  # Handle moving selected items from selected to available
  observeEvent(input$move_left, {
    selected <- get_selected_items()
    # Filter to only items in the selected list
    to_move <- intersect(selected, rv$selected)
    
    if(length(to_move) > 0){
      rv$selected <- setdiff(rv$selected, to_move)
      rv$available <- c(rv$available, to_move)
      # Uncheck checkboxes after moving
      session$sendCustomMessage("uncheck_all", list())
    }
  })
  
  # JavaScript to uncheck all checkboxes after movement
  tags$script(HTML("
    Shiny.addCustomMessageHandler('uncheck_all', function() {
      $('.item-checkbox').prop('checked', false);
      Shiny.setInputValue('checked_items', []);
    });
  "))
  
  # Display current selected items for feedback
  output$current_selections <- renderPrint({
    input$checked_items
  })
}

shinyApp(ui, server)

Key Features Explained

  • Reactive State Tracking: Uses reactiveValues to keep track of items in each container, ensuring the UI updates dynamically when items are moved.
  • Checkbox Multi-Selection: Each item has a checkbox, making it easy for users to select multiple items at once.
  • Batch Movement Buttons: Buttons trigger JavaScript to collect selected items, then update the lists in Shiny.
  • Dual Functionality: Users can still drag single items between containers (thanks to the connect parameter) or use batch selection for bulk moves.
  • Clean State Management: Automatically unchecks checkboxes after moving items to avoid confusion.

Alternative: Native Multi-Drag with Ctrl/Cmd

If you prefer holding Ctrl/Cmd to select multiple items and drag them together, you can customize the jQuery UI sortable options passed to orderInput. Add this to your orderInput call:

options = list(
  cancel = ".item-checkbox", # Prevent checkbox from interfering with drag
  selected = ".ui-selected",
  start = I("function(event, ui) {
    var selected = $(this).find('.ui-selected').not(ui.item);
    ui.item.data('items', selected);
  }"),
  stop = I("function(event, ui) {
    var items = ui.item.data('items');
    if(items) {
      items.appendTo(ui.item.parent());
    }
  }")
)

Then add CSS to highlight selected items:

.ui-selected { background-color: #a8d1ff; }

This lets users select multiple items with Ctrl/Cmd and drag them together, though it’s a bit more complex than the checkbox approach.


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 07:59:37