Search code examples
rshinyreactiveshinyappsselectinput

From two selectInputs in the server, how to make one dependent on another?


First of all, I am so sorry if the main question (the title) of the post is not clearly enough. I didn't how to write a question with my problem.

Well, the thing is that I have two select inputs. The main one: Dataset, which have 2 options: 1) Cars and 2) Iris. The other select input, it has information from the Cars' dataset and information from the Iris one.

I need to show the information from Cars if I select Cars and the information from Iris if I select Iris.

Now, my code is not able to do that. Simply it shows you the options to choose the datasets but in the second select input only shows the information from Cars.

I don't know how to do it, I have been a lot of posts but I couldn't get what I want. For example this post Filter one selectInput based on selection from another selectInput? was very similar and I thought that I could do something similar, but he doesn't use a dataset from R...

My code:

library(shiny)
ui <- fluidPage(
  
  titlePanel("Select a dataset"),
  
  sidebarLayout(
    sidebarPanel(
      selectInput("dataset", "Dataset",
                  choices = c("Cars" = "Cars", "Iris" = "Iris")),
      uiOutput("select_cars"),
      uiOutput("select_iris")
      
    ),
    
    mainPanel(
      verbatimTextOutput("text"),
      verbatimTextOutput("text2") 
    )
  )
)

server <- function(input, output) {
  
  cars <- reactive({
    data("mtcars")
    cars <- rownames(mtcars)
    return(cars)
  })
  
  iris <- reactive({
    data("iris")
    iris <- data.frame(unique(iris$Species))
    colnames(iris) <- "iris"
    return(iris)
  })
  
  output$select_cars <- renderUI({
    selectInput(inputId = "options_cars", "Select one", choices = cars())
  })

  output$select_iris <- renderUI({
    selectInput(inputId = "options_iris", "Select one iris", choices = iris())
  })

  output$text <- renderPrint(input$options_cars)
  output$text2 <- renderPrint(input$options_iris)
}

#Run the app
shinyApp(ui = ui, server = server)

On the other hand I get an error: object of type ‘closure’ is not subsettable. But I don't know why.

Finally, I apologize if someone has already asked something similar before, I really have been looking all morning and I do not know how to solve it. (I am quite new at Shiny and I am trying to do my best).

Thanks very much in advance,

Regards


Solution

  • I have modified some of your code and added some JS functionality from shinyjs, which you may or may not find useful

    • You don't really need to create objects all the time if you only going to update the list, so we are going to use updateSelectInput to update the sliders
    • I used hidden functionality to hide the elements initially so they are invisible to begin with
    • I created dependency on input$dataset within observeEvent so we can update the sliders and hide and show both the sliders we dont want and the output we dont want
    • Also if your datasets are static, like mtcars and iris its best to take them outside the server.R so you dont do extra unnecessary work
    • Finally its always a good idea to add req so you're not creating any objects if they are NULL
    • Your original error was due to the fact that you were passing the dataframe and not the list or vector to the slider, try to print out the objects if you're unsure and see their types

    library(shiny)
    library(shinyjs)
    
    ui <- fluidPage(
        titlePanel("Select a dataset"),
        useShinyjs(),
        
        sidebarLayout(
            sidebarPanel(
                selectInput("dataset", "Dataset",
                            choices = c("Cars" = "Cars", "Iris" = "Iris")),
                hidden(selectInput(inputId = "options_cars", "Select one", choices = NULL)),
                hidden(selectInput(inputId = "options_iris", "Select one iris", choices = NULL))
                
            ),
            mainPanel(
                verbatimTextOutput("text_cars"),
                verbatimTextOutput("text_iris") 
            )
        )
    )
    
    cars_data <- unique(rownames(mtcars))
    iris_data <-  as.character(unique(iris$Species))
    
    server <- function(input, output, session) {
        
        observeEvent(input$dataset,{
            if(input$dataset == "Cars"){
                show('options_cars')
                hide('options_iris')
                show('text_cars')
                hide('text_iris')
                updateSelectInput(session,"options_cars", "Select one", choices = cars_data)
            }else{
                show('options_iris')
                hide('options_cars')
                show('text_iris')
                hide('text_cars')
                updateSelectInput(session,"options_iris", "Select one iris", choices = iris_data)
            }
        })
        
        output$text_cars <- renderPrint({
            req(input$options_cars)
            input$options_cars
        })
        
        output$text_iris <- renderPrint({
            req(input$options_iris)
            input$options_iris
        })
    }
    
    #Run the app
    shinyApp(ui = ui, server = server)