Search code examples
rshinyreactive

How can I update a subset of values in Shiny once, rather than having it update every time and undoing previous selections?


I want to be able to update my table based on filtering on values within a column, based on a user-provided .csv. The code below works to get my fields populated correctly, but the filtering function is not working correctly, as it re-updates the flow and cancels out any selection I make of a value.


ui <- fluidPage(
  fileInput("data", "Load Data", accept = ".csv"),
  selectInput("column", "Column", character()),
  selectInput("level", "level", "select"),
  dataTableOutput("table")
)

server <- function(input, output, session){
  options(shiny.maxRequestSize=1000*1024^2)
  data <- reactive({
    req(input$data)
    read.csv(input$data$datapath)
  })
  
  observeEvent(data(), {
    updateSelectInput(session, "column", choices = names(data()))
  })
  
  observeEvent(input$column, {
    val <- data()[[input$column]]
    updateSelectInput(session, "level", choices = val,
                      label = paste("Choose level in", input$column))
  })
  
  output$table <- renderDataTable({
    req(input$level)
    filter(data(), input$level == input$level)
  })
}  

shinyApp(ui = ui, server = server)

I have also tried a dplyr solution for filtering,

     filter(input$value == input$value)

but that's not working either, for the same reason. I'm relatively new to Shiny, so any and all assistance and resources are appreciated.


Solution

  • Perhaps you were looking for something like this?

    Using the .data pronoun. More information here.

    library(shiny)
    library(readr)
    library(dplyr)
    
    ui <- fluidPage(
      fileInput("data", "Load Data", accept = ".csv"),
      selectInput("column", "Column", character()),
      selectInput("level", "level", "select"),
      dataTableOutput("table")
    )
    
    server <- function(input, output, session) {
      options(shiny.maxRequestSize = 1000 * 1024^2)
      data <- reactive({
        req(input$data)
        read_csv(input$data$datapath)
      })
    
      observeEvent(data(), {
        updateSelectInput(session, "column", choices = names(data()))
      })
    
      observeEvent(input$column, {
        val <- data()[[input$column]]
        updateSelectInput(session, "level",
          choices = unique(val),
          label = paste("Choose level in", input$column)
        )
      })
    
      output$table <- renderDataTable({
        req(input$column)
        req(input$level)
        filter(data(), .data[[input$column]] == input$level)
      })
    }
    
    shinyApp(ui = ui, server = server)
    

    Tested with iris.csv created with write_csv(iris, "iris.csv")

    enter image description here