SaferSky
SaferSky

Reputation: 37

R Shiny - How to update a SINGLE input with Multiple input methods

I want to use TWO methods to update a SINGLE input.
Let say I want to use NumericInput and SliderInput.

When I update my NumericInput to 5, the SliderInput should update to 5.
Whatever I said above, I've seen many examples.
But how do I do it the other way around? (update each other)
Now If I update the SliderInput to 6, how to get my NumericInput updated to 6?

Heres what I've tried but didn't work:

ui <- fluidPage(
numericInput("year", "", min = 1979, max = 2017, value = 1979),
sliderInput("year", "Select Year", min = 1979, max = 2017, value = 1979)
)

#===================================================

server <- function(input, output, session) {
  observe(input$year,  {
    updateSliderInput(session, "year", value = year)
  })

  observe(input$year,  {
    updateNumericInput(session, "year", value = year)
  })

Upvotes: 3

Views: 637

Answers (3)

TemplateRex
TemplateRex

Reputation: 70526

The answer by @hedgedandlevered does not scale to multiple inputs modifying the same state. It's easier to split the server into two parts: first let each UI element only modify the hidden state, and second, let each UI element observe that hidden state and update itself should it be out of sync.

With this approach, any UI element can remain completely ignorant of all other UI elements (so adding new or disabling old UI elements does not affect code for existing UI elements).

In effect, state is here the proverbial extra level of indirection that solves the problem.

ui <- fluidPage(
  numericInput("year1", "", min = 1979, max = 2017, value = 1979),
  sliderInput("year2", "Select Year", min = 1979, max = 2017, value = 1979),
  textOutput("variableprint")
)

server <- function(input, output, session) {
  # Hidden state
  state <- reactiveValues(year = NULL)
  
  # UI elements update the hidden state
  observeEvent(input$year1,  {
    if(!identical(state$year, input$year1)){
      print("update state 1") # for testing
      state$year <- input$year1
    }
  })
  observeEvent(input$year2,  {
    if(!identical(state$year, input$year2)){
      print("update state 2") # for testing
      state$year <- input$year2
    }
  })
  
  # state updates the out of sync UI elements
  observeEvent(state$year, {
    if (!identical(input$year1, state$year)) {
      print("update UI 1")
      updateNumericInput(session, "year1", value = state$year)
    }
    if (!identical(input$year2, state$year)) {
      print("update UI 2")
      updateSliderInput(session, "year2", value = state$year)
    }
  })
  output$variableprint <- renderText(state$year)
}

shinyApp(ui, server)

Upvotes: 0

hedgedandlevered
hedgedandlevered

Reputation: 2394

This prevents the problem of having each input refresh, since updating an input element will refresh it's corresponding input, which will trigger refreshing the original control. This does duplicate work, at best, and has unpredictable consequences or infinite looping at worst when combined with other functions. Updating a common, hidden variable solves this. It would also allow any number of controls to affect the variable without unnecessary refreshing taking place.

ui <- fluidPage(
  numericInput("year", "", min = 1979, max = 2017, value = 1979),
  sliderInput("year2", "Select Year", min = 1979, max = 2017, value = 1979),
  textOutput("variableprint")
)

#===================================================

server <- function(input, output, session) {
  reactiveVar <- reactiveValues(commonHiddenVar = NULL)
  observeEvent(input$year,  {
    if(identical(input$year, input$year2)){
      print("update1") #for testing
      reactiveVar$commonHiddenVar <- input$year
    } else {
      updateSliderInput(session, "year2", value = input$year)
    }
  })

  observeEvent(input$year2,  {
    if(identical(input$year, input$year2)){
      print("update2") #for testing
      reactiveVar$commonHiddenVar <- input$year2
    } else {
      updateNumericInput(session, "year", value = input$year2)
    }
  })
  output$variableprint <- renderText(reactiveVar$commonHiddenVar)
}

shinyApp(ui, server)

You'll notice that "update1" or "update2" will only print once. If these were added in the other answer, they would print both.

Upvotes: 2

LocoGris
LocoGris

Reputation: 4480

Do you mean something like this?

ui <- fluidPage(
  numericInput("year", "", min = 1979, max = 2017, value = 1979),
  sliderInput("year2", "Select Year", min = 1979, max = 2017, value = 1979)
)

#===================================================

server <- function(input, output, session) {
  observeEvent(input$year,  {
    updateSliderInput(session, "year2", value = input$year)
  })

  observeEvent(input$year2,  {
    updateNumericInput(session, "year", value = input$year2)
  })
}



shinyApp(ui, server)

Upvotes: 0

Related Questions