1
votes

while working on a Shiny application I stumbled upon the following problem which seems related to the order in which input are changed by the update***Input vs. the reactivity order.

I have been able to narrow down the code and steps to reproduce the problem to the following ones:

  • I have a numericInput which spans between 1 and 5, with 3 as default value, whose selected value is used to produce some output (for the sake of simplicity, here it's just a "Good" message if the value is 2, 3 or 4, and a "Bad" message if the value is either 1 or 5);
  • I want the user to be able to change the input value and either use its chosen value (by pressing a Submit button) or use the default value (by pressing a Reset button) in the rest of the application;
  • The check for the condition 1<value<5 has to be preferably inside an isolate block (because my actual complete code triggers various time-consuming operations based on the input)

The code snippets are the following

ui.R:

shinyUI(fluidPage(
    titlePanel(
        fluidRow(headerPanel(HTML("Test a possible bug"),  windowTitle = "Test a possible bug")
        )
    ),
    mainPanel(
        tabsetPanel(
            tabPanel("Try this", br(),
                numericInput(inputId="foo", label="Input me", value=3,min=1, max=5),
                actionButton(inputId="reset", label="Use default"),
                actionButton(inputId="submit", label="Use new value"),br(),br(),br(),
                textOutput(outputId="bar")
            )
        )
    )
))


server.R:

shinyServer(function(input, output, session) {

    observeEvent(input$reset, {
        updateNumericInput(session=session, inputId="foo", value=3)
    })

    checkInput <- reactive({
        input$submit
        input$reset
        isolate({
            input$foo > 1 && input$foo < 5
        })
    })

    output$bar <- renderText({
        if (checkInput())
            "Good"
        else
            "Bad"
    })

})

The problem I encountered is the following

  1. If I choose 5, the app properly prints a "Bad" message
  2. If I now press "Use default" the numericInput is properly update to the default 3, but the message remains "Bad" because the modification of the input is not acknowledged (yet) by shiny
  3. If I now press a second time the "Use default" button, or if I press the "Use new value" button, the message is now correctly updated to "Good"

I would expect on the other hand that shiny acknowledges the updated input, since the input field has changed

Is this behaviour by design? Any suggestion to solve the problem? I could work around the issue by requiring the user to separately reset the value to default and then to submit the new value, but it sounds a little bit unsatisfactory...

p.s. my actual code has a dozen of numericInput fields, thus the "Use default" button is really needed because manually restoring all values is not really a feasible option outside the simplified settings posted here ;-)

1

1 Answers

0
votes

I believe this is how it is intended to work. If you check the documentation, of updateNumericInput or updateSelectInput, the updation is done after all the outputs are produced.

"The input updater functions send a message to the client, telling it to change the settings of an input object. The messages are collected and sent after all the observers (including outputs) have finished running."

I would suggest that the functionality be set in such a way that the Message "good' or 'bad' be displayed only when 'Submit' is hit, AND that it is 'cleared' when "Reset' is hit. Hope this is useful

Please see an example

library(shiny)

ui<-(fluidPage(
  titlePanel(
    fluidRow(headerPanel(HTML("Test a possible bug"),  windowTitle = "Test a possible bug")
    )
  ),
  mainPanel(
    tabsetPanel(
      tabPanel("Try this", br(),
               numericInput(inputId="foo", label="Input me", value=3,min=1, max=5),
               actionButton(inputId="reset", label="Use default"),
               actionButton(inputId="submit", label="Use new value"),br(),br(),br(),
               textOutput(outputId="bar")
      )
    )
  )
))

server<-(function(input, output, session) {
rv <- reactiveValues()

  observeEvent(input$reset, {
    updateNumericInput(session=session, inputId="foo", value=3)
     rv$Message = " "

  })
observeEvent(input$submit,{
  rv$checkInput<- input$foo > 1 && input$foo < 5

    if (rv$checkInput)
     rv$Message<- "Good"
    else
      rv$Message<-  "Bad"
})


  output$bar <- renderText({
    rv$Message
  })

})

shinyApp(ui,server)