在Shiny应用程序中同步两个rHandsontable输出之间的列顺序

n9vozmp4  于 2023-04-18  发布在  其他
关注(0)|答案(1)|浏览(115)

bounty明天到期。回答此问题可获得+50声望奖励。mat希望引起更多关注此问题。

我正在构建一个Shiny应用程序,它并排显示两个表:一个控制表和一个预览表。控制表显示预览表的列名,用户可以通过拖放列来改变它们的顺序。用户还可以编辑控制表中的列名,这些更改会反映在预览表中。但是,我在控制表和预览表之间同步列的顺序时遇到了问题。
以下是我的Shiny应用程序的代码:

library(shiny)
library(data.table)
library(htmlwidgets)
library(rhandsontable)

ui <- fluidPage(
  fluidRow(column(width = 6, rHandsontableOutput('control_table')),
           column(width = 6, rHandsontableOutput('preview_table')))
)

server <- function(input, output) {
  # Reactive value
  rv_data <- reactiveVal(data.table(A = 1:3, B = 4:6, C = 7:9))
  
  # Control table
  output$control_table <- renderRHandsontable({
    req(rv_data())
    
    # Get data
    DT <- rv_data()
    
    # Create table
    DTC <- data.table( t( names(DT) ) )
    setnames(DTC, names(DT))
    
    # Display table
    rhandsontable(
      data = DTC,
      readOnly = FALSE,
      contextMenu = FALSE,
      selectionMode = 'none',
      manualColumnMove = TRUE,
      afterColumnMove = JS(
        'function(changes, source) { Shiny.setInputValue("column_order", this.getColHeader()); }'
      )
    )
  })
  
  # Preview table
  output$preview_table <- renderRHandsontable({
    req(rv_data())
    
    # Get data
    DT <- rv_data()
    
    # Display table
    rhandsontable(
      data = DT,
      readOnly = TRUE,
      contextMenu = FALSE,
      selectionMode = 'none'
    )
  })
  
  # Change columns' names
  observeEvent(input$control_table$changes$changes, {
    # Get data
    DT <- rv_data()
    DT_hot <- hot_to_r(input$control_table)
    
    # Set new cols names
    names(DT) <- unlist(DT_hot[1, ])
    
    # Updated reactive value
    rv_data(DT)
  })
  
  # Change columns' order
  observeEvent(input$column_order, {
    # Get data
    DT <- rv_data()
    
    # Set new cols order
    new_col_order <- input$column_order
    DT <- DT[, ..new_col_order]
    
    # Updated reactive value
    rv_data(DT)
  })
}

shinyApp(ui, server)

更改控制表中列的顺序时,预览表中的列不会相应更新。我尝试了几种方法,但无法使列的顺序在控制表和预览表之间同步。如何实现此同步?

vnzz0bqm

vnzz0bqm1#

下面是使用library(sortable)的方法:

library(shiny)
library(data.table)
library(htmlwidgets)
library(rhandsontable)
library(sortable)

DT <- data.table(A = 1:3, B = 4:6, C = 7:9)
initial_column_names <- names(DT)
inputIds <- paste0("textInput", seq_along(initial_column_names))
labels <- setNames(lapply(seq_along(initial_column_names), function(i){textInput(inputId = inputIds[i], label = "", value = initial_column_names[i], width = NULL, placeholder = NULL)}), inputIds)

column_rank_list <- rank_list(
  text = "Reorder / rename columns",
  labels = labels,
  input_id = "column_rank_list"
)

ui <- fluidPage(
  fluidRow(column(width = 3, column_rank_list),
           column(width = 9, rHandsontableOutput('preview_table')))
)

server <- function(input, output, session) {
  rv_data <- reactiveVal(DT)
  
  # Change columns' order
  observeEvent(input$column_rank_list, {
    req(input$column_rank_list)
    tmpDT <- copy(rv_data())
    column_order <- sapply(input$column_rank_list, function(x){input[[x]]})
    setcolorder(tmpDT, column_order)
    rv_data(tmpDT)
  })
  
  # Change column names
  observeEvent(sapply(inputIds, function(x){input[[x]]}), {
    req(input$column_rank_list)
    tmpDT <- copy(rv_data())
    column_order <- sapply(input$column_rank_list, function(x){input[[x]]})
    setnames(tmpDT, column_order)
    rv_data(tmpDT)
  })
  
  # Preview table
  output$preview_table <- renderRHandsontable({
    rhandsontable(
      data = rv_data(),
      readOnly = TRUE,
      contextMenu = FALSE,
      selectionMode = 'none'
    )
  })
}

shinyApp(ui, server)

如果您喜欢水平布局,请选中this

相关问题