1

I have been following the solution provided in this post to update the names and column order of a dataset in a Shiny app. The original solution used a dummy dataset, but now I want to extend this solution to for a dataset (e.g., uploaded by the user) with an unknown number of columns in advance. How can I achieve this?

This is what I have tried so far:

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

ui <- fluidPage(
  fluidRow(column(width = 3, uiOutput('ui_rank_list')),
           column(width = 9, 
                  actionButton('gen_test_data', label = 'Generate test data'),
                  tableOutput('preview_table')))
)

server <- function(input, output, session) {
  rv_data <- reactiveVal()
  
  # Generate some test data
  observeEvent(input$gen_test_data, {
    nrows <- 5
    ncols <- sample(2:10, 1) # This number is in fact unknown
    col_names <- replicate(ncols,
                           paste0(c(sample(letters, 4, replace = TRUE),
                                    sample(10:100, 2, replace = TRUE)), collapse = ''))
    DT <- data.table(matrix(1:(5*ncols), ncol = ncols))
    setnames(DT, col_names)

    rv_data(DT)
  })
  
  # Generate UI for selecting data set as well as buttons
  output$ui_rank_list <- renderUI({
    req(rv_data(), rv_labels())
    
    DT <- copy(rv_data())
    inputIds <<- paste0("textInput", seq_along(names(DT)))
    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"
    )
    column_rank_list
  })
  
  # 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 <- renderTable({
    req(rv_data())
    rv_data()
  })
}

shinyApp(ui, server)

I return the following error: Error in lapply: object 'inputIds' not found

mat
  • 2,412
  • 5
  • 31
  • 69

1 Answers1

-1

Maybe you didn't put the parentheses there, in # Generate UI for selecting data set as well as buttons:

replace this

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)

to

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

To solve such problems, you should consider “Debugging”, for example, by this.

And you shouldn't use global variables at all, because it makes the code, for example, unpredictable.

In general, package dplyr with functions rename(), relocate() and tidy select can be used to manipulate a data frame.

roma
  • 25
  • 8