observeEvent does not seem to depend on its first argument changing state?

345 views
Skip to first unread message

Kevin Little

unread,
Nov 18, 2015, 3:23:02 PM11/18/15
to Shiny - Web Framework for R

This question is related to other posts on clearing Shiny app inputs but I can't find guidance yet that explains the behavior I'm seeing.

here is the shiny app example shiny::runGist("e1c0482c22348d934e71") 

The example app has a submit and clear button to allow repeated entry of data by the user.   The real app is connected to a Google Sheet which accumulates records. Each record has many elements (names, dates, etc); it also connects to SurveyMonkey API if certain conditions are met--all that functionality is working. 

I'm just hung up on the submit and clear logic.

What I expect to have happen in the example app:

users enters name and clicks Submit.   Data table updates.  After the Clear button is clicked, the shinyjs::reset function clears the text input field.   From the help file for the reset function:

"Reset any input element back to its original value. You can either reset one specific input at a time by providing the id of a shiny input, or reset all inputs within an HTML tag by providing the id of an HTML tag.

Reset can be performed on any traditional Shiny input widget, which includes: textInput, numericInput, sliderInput, selectInput, selectizeInput, radioButtons, dateInput, dateRangeInput, checkboxInput, checkboxGroupInput. Buttons are not supported, meaning that you cannot use this function to reset the value of an action button back to 0."

So, when the reset function executes, I expect the state of the Submit button to stay in its current state (it has been clicked ONCE).

The submit_check1 reactive function executes when the Clear button is clicked as the state of the input$champ_name has changed; it prints out the error message "Enter name".   

(This is acceptable behavior for now.)

Here's the part I don't understand:

it looks like the reactive functions sheet_confirmation and df1_out are both executing once the name box is filled in, even though these functions are contained within an observeEvent function.  I thought the observeEvent function requires a change in state of submit button to execute, given its first argument.   In other words, I expect to have to click the Submit button to get those functions to execute but that's not the case.

Can anyone explain why?

Thanks

here is the shiny app example shiny::runGist("e1c0482c22348d934e71") 

and here is the script   app.R:
#######################################################################
#test app to load the form and clear it for second record entry
#Kevin Little, Ph.D.  18 Nov 2015 

require(shiny)
require(shinyapps)
require(shinyjs)

#local df taking the place of a Google sheet
df1 <- data.frame(name="name1", stringsAsFactors = FALSE)

ui <- fluidPage(
  
   useShinyjs(),
   div(id="form_app",
      textInput(
        inputId = "champ_name",
        label   = "Your name",
        value   = "")
  ),
  actionButton(inputId = "submit", label="Submit"),
  actionButton(inputId = "ClearAll", label= "Clear"), 
  hr(),
  textOutput("sheet_confirmation"),
  tableOutput("table_output")
)

server <- function(input, output){

  submit_check1 <- reactive({
      champ_name <- input$champ_name
      conditions_met <- champ_name != ''
                            
      if (conditions_met) {
            out <- list(submit = TRUE, error_message = NULL)
      }                 
      else {
            out <- list(submit = FALSE)
            if(champ_name== '') error_message <- "Enter name"
            out$error_message <- error_message
      }
      return(out)
    })
   #This is where I expect to need input$submit to change state before the functions
    #sheet_confirmation and df1_out execute.
    observeEvent(input$submit, {
        sheet_confirmation <- reactive({
        champ_name    <- input$champ_name
        conditions <- submit_check1()
         if(conditions$submit) {
           out <- sprintf("Table updated")
         }
                     else {
            out <- conditions$error_message
          }
         out
      })
      
        df1_out <- reactive({
        champ_name <- input$champ_name
        conditions <- submit_check1()
        if(conditions$submit) {
          output_sheet_row <- data.frame(name=champ_name)
          #add a row to the data frame
          df1 <- rbind.data.frame(df1,output_sheet_row)
        }
        return(df1)
      })
      
      output$sheet_confirmation <- renderText(sheet_confirmation())
      output$table_output <- renderTable(df1_out())
    })
    
      observeEvent(input$ClearAll, {
      reset("form_app")
    })
  }

shinyApp(ui, server)
#################################################################
here's the state of my local system:

> sessionInfo:
R version 3.2.2 (2015-08-14)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 7 x64 (build 7601) Service Pack 1

locale:
[1] LC_COLLATE=English_United States.1252  LC_CTYPE=English_United States.1252   
[3] LC_MONETARY=English_United States.1252 LC_NUMERIC=C                          
[5] LC_TIME=English_United States.1252    

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] shinyjs_0.2.0    shinyapps_0.3.63 shiny_0.12.2    

loaded via a namespace (and not attached):
 [1] R6_2.1.1         htmltools_0.2.6  tools_3.2.2      rstudioapi_0.3.1 Rcpp_0.12.1     
 [6] jsonlite_0.9.17  digest_0.6.8     xtable_1.7-4     httpuv_1.3.3     mime_0.4        

Joe Cheng

unread,
Nov 18, 2015, 4:44:46 PM11/18/15
to Kevin Little, Shiny - Web Framework for R
OK, couple of things here. The reset button is a little bit of a red herring; you can see that even if you don't click reset, once you've hit Submit changing the name using any method will cause the outputs to update.

Your code would make sense if output$foo <- renderBar(...) meant "Update the output 'foo' with the value returned by renderBar(...)". But that's not what output$foo <- renderBar(...) means; it means, "This here is a recipe for rendering a Bar, it should be used continually from now on to populate the 'foo' output." So while the line `output$sheet_confirmation <- renderText(sheet_confirmation())` is only executed when the submit button is clicked, that's enough to keep sheet_confirmation up to date from then on.

Similarly, just because these reactive expressions sheet_confirmation and table_output happen to be created inside an observeEvent, they themselves are just regular reactive expressions--when their dependencies (input$champ_name) changes, they invalidate.

If you find yourself either creating a reactive expression or assigning an output slot inside of an observe() or an observeEvent(), it's almost always a sign that you're on the wrong track.

I've posted a fixed version here: https://gist.github.com/jcheng5/9cadfad7751f20cd957a It uses a champ_name eventReactive to wrap input$champ_name. I also do validation there, which means we don't need sheet_confirmation anymore. See http://shiny.rstudio.com/articles/validation.html and https://www.youtube.com/watch?v=7sQ6AEDFjZ4 for more on validation.



--
You received this message because you are subscribed to the Google Groups "Shiny - Web Framework for R" group.
To unsubscribe from this group and stop receiving emails from it, send an email to shiny-discus...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/shiny-discuss/7a6b7c91-a237-4878-bd1a-2d7470c97b76%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Kevin Little

unread,
Nov 19, 2015, 3:25:43 PM11/19/15
to Shiny - Web Framework for R, kli...@iecodesign.com
Thank you Joe foe clear explanation and sample code turned around very fast.   I follow what you're saying and now have a better understanding of reactive events.   Using the eventReactive function works great.   Starting to build out the real app.  than you again!
Reply all
Reply to author
Forward
0 new messages