Update input UI when calling Shiny.setInputValue

Viewed 613

Consider this sample shiny application. You can type in a car name like "Valiant" and it will print out the MPG value from the mtcars built-in data set. I also wanted to allow the user to click on a car rather than type it. I did this by generating a list of links with car names and writing a bit of javascript to call Shiny.setInputValue when the link is clicked.

I noticed that when a link is clicked, the server state updates (ie the textOutput("MPG") value changes) but the text box doesn't update to show the current value. Is there a different way to get the value such that the textInput is updated AND the reactive textOutput is updated?

library(shiny)

script <- "$(document).on('click', '.name-opt a', function (evt) {
  evt.preventDefault(); Shiny.setInputValue('name',this.dataset.name);
});"

ui <- fluidPage(
  tags$head(tags$script(HTML(script))),
  textInput("name", "Name:"),
  textOutput("MPG"),
  uiOutput("carlist")
)

server <- function(input, output, session) {
  output$carlist <- renderUI({
    tags$ul(
      Map(function(v) tags$li(tags$a(v, href="#", "data-name"=v)), rownames(head(mtcars, 20))), 
      class="name-opt")
  })
  output$MPG <- renderText({
    req(input$name)
    paste(input$name, "mpg:", mtcars[input$name,]$mpg)
  })
}

shinyApp(ui, server)

Tested with shiny_1.5.0

1 Answers

Serverside: You have to make a reactive value, here: myinput, and then call its value with myinput(). Then you need observer that fires the updateTextInput whenever myinput() changes

 myinput = reactive({
    paste(input$name)
  })
  
  observeEvent(myinput(),{
  updateTextInput(session, "name", value = myinput())
  })

The whole code:

library(shiny)

script <- "$(document).on('click', '.name-opt a', function (evt) {
  evt.preventDefault(); Shiny.setInputValue('name',this.dataset.name);
});"

ui <- fluidPage(
  tags$head(tags$script(HTML(script))),
  textInput("name", "Name:"),
  textOutput("MPG"),
  uiOutput("carlist")
)

server <- function(input, output, session) {
  output$carlist <- renderUI({
    tags$ul(
      Map(function(v) tags$li(tags$a(v, href="#", "data-name"=v)), rownames(head(mtcars, 20))), 
      class="name-opt")
  })
  output$MPG <- renderText({
    req(input$name)
    paste(input$name, "mpg:", mtcars[input$name,]$mpg)
  })
  
  myinput = reactive({
    paste(input$name)
  })
  
  observeEvent(myinput(),{
  updateTextInput(session, "name", value = myinput())
  })
}

shinyApp(ui, server)
Related