Reputation: 339
I am trying to change an inputs on Shiny using JS with an input from the server (so the value can be conditional). In this example I've fixed the value to 'NJ' but at the end id like this value to be dynamic. The end result I am trying to achieve is to get the dropdown menu to change to a value (here 'NJ') when the button is clicked. Working example below.
My JS knowledge is pretty light and most of it has come from reading the R documentation, such as the doc below.
https://shiny.rstudio.com/articles/communicating-with-js.html
library("shiny")
ui <- fluidPage(
tags$script("Shiny.addCustomMessageHandler('change_sel', function(x){
Shiny.setInputValue('state', x,{priority: 'event'});
});")
,
column(6,
selectInput("state", "Choose a state:",
c("NY", "NJ", "CT")
),
column(6,
actionButton("but1", "Change to NJ"
)
)))
server <- function(input, output, session) {
observeEvent(input$but1, {
session$sendCustomMessage("change_sel", "NJ")
})
observe(print(input$state))
}
shinyApp(ui, server)
Upvotes: 1
Views: 1352
Reputation: 669
If you are using shiny input components and would like to update the value of an input element by some other means (e.g., button click), then use one of the update-
functions (available in the shiny package). However, it is unlikely that these update functions will work (or are even available) for non-Shiny widgets.
One alternative is to create a custom input binding where data is sent between Shiny and the client. This approach is best for custom input components or for creating wrappers around existing component libraries (non-R/Shiny packages). (For more information, checkout the following RStudio guides Building Custom Input Objects and How to create custom input bindings. I won't go into detail here about input bindings as it would make for a long answer).
Messages can be sent from Shiny to the client using session$sendInputMessage()
. In the input binding (written using jQuery; vanilla JS won't work), use the receiveInputMessage
method to retrieve and respond to the data. Using the example provided in your question, I provided a demo on how to update a custom select input widget in response to a button click.
Let me know if you have any questions!
library(shiny)
ui <- tagList(
tags$main(
tags$h1("Receive Message Input"),
tags$label(
`for` = "state",
"Select a State"
),
tags$select(
id = "state",
class = "select__input",
tags$option(value = "NONE", "--- Select ---"),
tags$option(value = "NY", "New York"),
tags$option(value = "NJ", "New Jersey"),
tags$option(value = "CT", "Connecticut")
),
tags$button(
id = "state_ny",
class = "shiny-bound-input action-button",
"Select New York"
),
tags$button(
id = "state_nj",
class = "shiny-bound-input action-button",
"Select New Jersey"
),
tags$button(
id = "state_reset",
class = "shiny-bound-input action-button",
"Reset"
)
),
tags$script(
type = "text/javascript",
HTML(
"const myCustomBinding = new Shiny.InputBinding();",
"$.extend(myCustomBinding, {
find = function(scope) {
return $(scope).find('.select__input');
},
getValue = function(el) {
return $(scope).value;
},
subscribe = function(el, callback) {
$(el).on('change', function(e) {
callback();
});
},
receiveInputMessage = function(el, message) {
if (message.type === 'update') {
$(el).value = data.value
}
},
unsubscribe = function(el) {
$(el).off('myCustomBinding');
}
});",
"Shiny.inputBindings.register(myCustomBinding);"
)
)
)
server <- function(input, output, session) {
# server-side function for sending data for use in `receiveInputMessage`
setSelectValue <- function(inputId, value) {
session$sendInputMessage(
inputId = inputId,
message = list(
type = "update",
value = value
)
)
}
# onClick Events
observeEvent(input$state_ny, setSelectValue("state", "NY"))
observeEvent(input$state_nj, setSelectValue("state", "NJ"))
observeEvent(input$state_reset, setSelectValue("state", "NONE"))
observe(print(input$state))
}
shinyApp(ui, server)
Upvotes: 1