How do I make two observeEvent function for different options in selectinput

The result page in my program aims to respond differently to the different options the user enters. I feel observeEvent seems relevant but when I wrote this way it only displays the latest observeEvent (which is the female one).

Here is the simplified version of my code:

library(shiny)

ui <- fluidPage(

mainPanel(tabsetPanel(type = "tabs",
                    tabPanel("Personal Information", 
                             selectInput("gender","What is your biological gender?:",c("--" = "null","male" = "gender1","female" = "gender2"))
                    ),
                    tabPanel("Result", verbatimTextOutput("result"))
  )))

server <- function(input, output) { 


observeEvent({input$gender == "gender1"},output$result <- renderPrint ("You are a male."))
observeEvent({input$gender == "gender2"},output$result <- renderPrint ("You are a female."))

}

shinyApp(ui, server)
rshiny

Answers

answered 4 months ago divibisan #1

You should use one observeEvent that triggers whenever input$gender changes. Then have a conditional inside that which determines what value to return. You actually don't need the observeEvent at all, since any reactive expression (including a renderPrint) will update if any reactive values in it are invalidated. So the best way to do what you want is to replace bout observeEvent functions with the below:

output$result <- renderPrint({
    if (input$gender == 'gender1') {
        return("You are a male.")
    } else if (input$gender == 'gender2') {
        return("You are a female.")
    }
})

The difference with using an event function vs a render* is that the code block is considered to be in an isolate block and only the change of the eventExpr will trigger the code to run. That's good if you want to make the code only run when an Update button is pressed, but if you want it to be reactive to changing values (like in your example) you shouldn't use an event function.

Also, you are strongly encouraged not to nest reactive expressions as you do above. If you must have an event function drive a renderPrint function (as in your example), the reccomended way of doing that is with an eventReactive:

gender_input <- eventReactive(input$update, {
    if (input$gender == 'gender1') {
        return("You are a male.")
    } else if (input$gender == 'gender2') {
        return("You are a female.")
    }
})

output$result <- renderPrint({gender_input()})

answered 4 months ago SeGa #2

Or you could place all in 1 observeEvent and depending on the condition, change the desired text and use it then in a renderPrint function like this:

server <- function(input, output) { 
  observeEvent(input$gender, {
    if (input$gender == "gender1") {
      txt <- "You are a male."
    } else if (input$gender == "gender2") {
      txt <- "You are a female."
    } else {
      txt <- NULL
    }
    output$result <- renderPrint(txt)
  })
}

Allthough i would also favor the solution from @divibisan.

You could although use a reactiveValue, where the text is stored. In this way, you can access the text everywhere in your server function and you dont have to nest the rnderPrint function inside the observeEvent. This is what you would do with the server function:

server <- function(input, output) { 

  reactTXT <- reactiveValues(txt=NULL)

  observeEvent(input$gender, {
    if (input$gender == "gender1") {
      txt <- "You are a male."
    } else if (input$gender == "gender2") {
      txt <- "You are a female."
    } else {
      txt <- NULL
    }
    reactTXT$txt <- txt
  })

  output$result <- renderPrint({
    reactTXT$txt
    })
}

First you create the reactiveValue reactTXT. In the observeEvent you assign the text to the reactiveValue with reactTXT$txt <- txt. And in the renderPrint function you just pass the reactiveValue reactTXT$txt to print it.

comments powered by Disqus