User Input is not displayed and not editable after adding columns

Dear R-community,

I am trying to build an app with R shiny. I am using selectInput() and textInput() in cells of a table. Moreover, I want the user to be able to click a button to add a column in the table with those input fields. the problem is, that when I add a column, the entered values in the first column are saved, but not displayed, and if I re-enter some values in the first column, it doesn't change the already saved values.

I built a mock example to demonstrate my problem:

#load data
data <- data.frame(c = sample(c("A", "B"), 300, replace = TRUE), v = sample(c("w", "x"), 300, replace = TRUE), s = sample(c("FF", "GG", "HH"), 300, replace = TRUE))
data <- data[!duplicated(data),]
data <- data[order(data$c, data$v, data$s),]

numb_of_c <- length(unique(data$c))

ui <- dashboardPage(
  dashboardHeader(title = "TEST",
                  titleWidth = 450), 
    width = 450,
      lapply(1:numb_of_c, function(i) {
        menuItem(unique(data$c)[i], tabName = unique(data$c)[i])
    box(actionButton("add_col", label = "Add column"),
        actionButton("rm_col", label = "Remove column"),

server <- function(input, output, session) {

  #counter for number of columns
  counter <- reactiveValues(n = 0)
  observeEvent(input$add_col, {counter$n <- counter$n + 1})
  observeEvent(input$rm_col, {
    if (counter$n > 0) counter$n <- counter$n - 1
  #ui for all c
  output$tab_items_output <- renderUI({
    theitems <- list()
    for (i in 1:numb_of_c) {
      theitems[[unique(data$c)[i]]] <- tabItem(tabName = unique(data$c)[i],
                                                       box(width = 12,
                                                           uiOutput(outputId = paste0("ui_", unique(data$c)[i]))
    theitems <- unname(theitems), theitems)
  #ui for each c
  lapply(1:numb_of_c, function(i) {
    gen_cols <- reactive({
      #get data frame of current c
      temp <- data[data$c==unique(data$c)[i],]
      # Create selectInput and textInput objects to embed in table
      table_inputs <- character(nrow(temp))
      for (y in 1:(counter$n+1)) {
        for (x in 1:nrow(temp)) {
          if (temp$s[x]=="HH") { #if categorical
            table_inputs[x] <- as.character(selectInput(paste0(as.character(temp$c[x]), as.character(temp$v[x]), as.character(temp$s[x]), y), label = NULL, choices = 1:5))
          else {
            table_inputs[x] <- as.character(textInput(paste0(temp$c[x], temp$v[x], temp$s[x], y), label = NULL, value = NULL)) 
        temp <- cbind(temp, table_inputs)
    #create ui of table
    output[[paste0("ui_", unique(data$c)[i])]] <- renderUI({
          fluidRow(dataTableOutput(outputId = paste0("table_", gen_cols()$c[i]))
    #table ui
    output[[paste0("table_", data[data$c==unique(data$c)[i],"c"][i])]] <- DT::renderDataTable(
      selection = 'none',
      server = FALSE,
      escape = FALSE,
      rownames = FALSE,
      options = list(
        scrollX = TRUE,
        paging = TRUE,
        pageLength = 100,
        lengthMenu = c(5, 10, 20, 100),
        preDrawCallback = JS('function() { 
                             Shiny.unbindAll(this.api().table().node()); }'), 
        drawCallback = JS('function() { 
                          Shiny.bindAll(this.api().table().node()); } '))
  output$printtext <- renderPrint(print(input[["AwFF1"]]))

shinyApp(ui, server)

When I am entering a value of 1, I can easily access it as can be seen in the verbatimTextOutput:

When I then add a column, the 1 is still saved in the first textInput, but the textInput field is empty:

And if I try to change the value, it doesn't seem to accept any edits.

I tried to solve it somehow by including:

AllInputs <- reactive({
      x <- reactiveValuesToList(input)

and then setting the value in the input fields, but the app kept refreshing itself:

table_inputs[x] <- as.character(textInput(paste0(temp$c[x], temp$v[x], temp$s[x], y), label = NULL, value = AllInputs()[[paste0(temp$c[x], temp$v[x], temp$s[x], y)]]))

Any help would be much appreciated!


I think it's much easier if you use the editable datatable from the DT package. I don't know for sure if that will satisfy your needs, but it certainly gives an easy way to edit a table on the go. You can simply double click any cell in the table to edit it.

Here is an example:


ui <- fluidPage(
  headerPanel("Editable table app"),
  actionButton("addColumn", "Add Column"),

server <- function(input, output, session) {
  #Original data
  myData = reactiveVal(data.frame(x = 1:10, y = round(runif(10),2), 
                                       z = LETTERS[1:10], stringsAsFactors = FALSE))
  #Data table output
  output$myTable = renderDT({
    datatable(myData(), editable = T, selection = "single")
  #Code when column is added
  observeEvent(input$addColumn, {
    #Add a column name on the go (based on number of times button is clicked)
    myData(myData() %>% mutate(!!(paste0("newColumn", input$addColumn)) := 0))
  }, ignoreInit = T)
  #Code to update server-side data when edited on client side
  observeEvent(input$myTable_cell_edit, {
    editCell = input$myTable_cell_edit
    #In order to update the reactive data, make it local first
    myData = myData()
    #...then update
    myData[editCell$row, editCell$col] = editCell$value
    #...then update the reactive again
  }, ignoreInit = T)

shinyApp(ui, server)

Hope this helps,

1 Like

Hey PJ,

thank you for your reply. I added stringsAsFactors = FALSE to the generation of myData, because otherwise it won't properly save changes if you enter 'invalid factor levels' and instead generates NA values.



That's good to know, I updated the stringsAsFactors in the example!


This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.