Update DT table dropdowns with reactive data in shiny

I am trying to extend the code described by Yihui Xie here https://rstudio.github.io/DT/011-radio.html and implemented as dropdowns here: https://stackoverflow.com/questions/57215607/render-dropdown-for-single-column-in-dt-shiny/57218361#57218361 by using reactive data instead of a static data frame.

The code creates inputs (selectInput in this case) within a DT table.

However, I'm having trouble updating user inputs in the drop downs when the input data changes.

In this example, the code works fine until the numeric input changes. After changing the numericInput, the output from the rows which existed is no longer updated.

I've tried a million variants of resetting the data as well as using editable = TRUE and dataTableProxy without any luck. How could this strategy be implemented with reactive data?

Thanks!

library(shiny)
library(DT)

ui <- fluidPage(
  title = 'Selectinput column in a table',
  h3("Source:", tags$a("Yihui Xie", href = "https://yihui.shinyapps.io/DT-radio/")),
  numericInput('num', "enter a number", value = 5, min = 1, max = 10, step = 1),
  DT::dataTableOutput('foo'),
  verbatimTextOutput('sel')
)

server <- function(input, output, session) {
  data <- reactive({
    df <- head(iris, input$num)
    
    for (i in 1:nrow(df)) {
      df$species_selector[i] <- as.character(selectInput(paste0("sel", i),
                                                           "",
                                                           choices = unique(iris$Species),
                                                           width = "100px"))
    }
    df
  })
  
  output$foo = DT::renderDataTable(
    data(), escape = FALSE, selection = 'none', server = FALSE,
    options = list(dom = 't', paging = FALSE, ordering = FALSE),
    callback = JS("table.rows().every(function(i, tab, row) {
        var $this = $(this.node());
        $this.attr('id', this.data()[0]);
        $this.addClass('shiny-input-container');
      });
      Shiny.unbindAll(table.table().node());
      Shiny.bindAll(table.table().node());")
  )
  output$sel = renderPrint({
    str(sapply(1:nrow(data()), function(i) input[[paste0("sel", i)]]))
  })
}

shinyApp(ui, server)

I think the problem is that you are re-using the selectInput id's while they have not been cleared from the page yet. One way you can overcome this is by generating new id's each time the number is changed. There could be better/more efficient solutions but this seems to work.

library(shiny)
library(DT)

ui <- fluidPage(
  title = 'Selectinput column in a table',
  h3("Source:", tags$a("Yihui Xie", href = "https://yihui.shinyapps.io/DT-radio/")),
  numericInput('num', "enter a number", value = 5, min = 1, max = 10, step = 1),
  DT::dataTableOutput('foo'),
  verbatimTextOutput('sel')
)

server <- function(input, output, session) {
  
  counter <- reactiveVal(0)
  get_sel_id <- reactive({
    input$num
    isolate(counter(counter() + 1))
    paste0("sel", counter())
  })
  
  data <- reactive({
    df <- head(iris, input$num)
    
    for (i in 1:nrow(df)) {
      df$species_selector[i] <- as.character(selectInput(paste0(get_sel_id(), i),
                                                           "",
                                                           choices = unique(iris$Species),
                                                           width = "100px"))
    }
    df
  })
  
  output$foo = DT::renderDataTable(
    data(), escape = FALSE, selection = 'none', server = FALSE,
    options = list(dom = 't', paging = FALSE, ordering = FALSE),
    callback = JS("table.rows().every(function(i, tab, row) {
        var $this = $(this.node());
        $this.attr('id', this.data()[0]);
        $this.addClass('shiny-input-container');
      });
      Shiny.unbindAll(table.table().node());
      Shiny.bindAll(table.table().node());")
  )
  output$sel = renderPrint({
    str(sapply(1:nrow(data()), function(i) input[[paste0(get_sel_id(), i)]]))
  })
}

shinyApp(ui, server)

Yes! thank you so much. That worked perfectly. I see how I was trying to overwrite input$sel1 as the inputs were created reactively.

I don't mind the inefficiency. Perhaps I'll use shinyjs:: refresh and encourage the user to "reset" if things seem to bog down from generating too many id's.

1 Like

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

If you have a query related to it or one of the replies, start a new topic and refer back with a link.