I'm building a Shiny app where elements of the output can be clicked to set input variables. I'm doing so by including some Javascript that calls the Shiny.setInputValue
method.
I'd like to initialize these values but don't want the user to be aware of them, since they're only used behind the scenes. My current hack is to use the hidden
function from the shinyjs
library around some buttons in the ui, but that's not very satisfying. Here's an example of my approach:
library(shiny)
library(shinyjs)
library(tidyverse)
ui <- fluidPage(
useShinyjs(),
hidden(
numericInput(label = NULL, inputId = 'INPUT', value = 0)
),
DT::dataTableOutput("one_row")
)
server <- function(input, output) {
script <- 'Shiny.setInputValue("INPUT", Math.random());'
btn <- as.character(actionButton(inputId = 'button',
label = "Click me!",
onclick = script))
one_row <- iris[1, ] %>% mutate(button = btn)
output$one_row <- DT::renderDataTable({
print(input$INPUT)
one_row}, escape = FALSE)
}
shinyApp(ui = ui, server = server)
So my main question is: is there a better way to set the default of these "invisible" inputs? Should I just use the runjs
function somewhere in the app?
A related question is: is it possible to access these input values using javascript? I was hoping there was something like Shiny.getInputValue
but there doesn't seem to be.
EDIT:
Here's a more thorough example that shows precisely what I'm trying to do. I'm usingvisNetwork
, but I'd like to override some of the default behavior. Usually, when you click on a node it shows all connected edges, incoming or outgoing.
I'd like a node selection to show only edges in one direction, and then to show the other direction if you click again (in, out, in, out, ...). To do so, I need to keep track of clicks (click
), which node is selected (selected_node
), and what direction to currently show (out
).
To accomplish this, I'm currently using visEvents
to redefine what happens on a click and visNetworkProxy
to select nodes and edges based on that click.
library(shiny)
library(shinyjs)
library(tidyverse)
library(visNetwork)
ui <- fluidPage(
useShinyjs(),
hidden(
numericInput(label = NULL, inputId = 'click', value = 0),
numericInput(label = NULL, inputId = 'selected_node', value = 0)
),
visNetworkOutput("network")
)
server <- function(input, output) {
network <- reactive({
nodes <- data.frame(id = 1:3)
edges <- data.frame(expand.grid(to = 1:3, from = 1:3)) %>%
mutate(id = row_number())
list(nodes = nodes, edges = edges)
})
output$network <- renderVisNetwork({
network <- network()
visNetwork(network$nodes, network$edges) %>%
visPhysics(enabled = FALSE) %>%
visLayout(randomSeed = 123) %>%
visEdges(smooth = list(type = 'curvedCW'),
arrows =list(to = list(enabled = TRUE, scaleFactor = 0.5))) %>%
visEvents(type = "on",
click = "function (properties) {
var nodeID = properties.nodes[0]
var edgeID = properties.edges[0];
if (nodeID) { Shiny.onInputChange('click', 1, {priority: \"event\"});
Shiny.onInputChange('selected_node', nodeID)}
else if (edgeID){ Shiny.onInputChange('click', 2);}
else { Shiny.onInputChange('click', 3);}}")
})
out <- FALSE
observe({
out <<- !out
nodeID <- input$selected_node
network <- network()
# only fire if node was selected
if(input$click == 1){
edgeIDs <- network$edges %>% filter(to == nodeID) %>%
pull(id)
if(out){edgeIDs <- network$edges %>% filter(from == input$selected_node) %>% pull(id)}
visNetworkProxy("network") %>%
visSetSelection(nodesId = nodeID, edgesId = edgeIDs, highlightEdges = FALSE)
}
})
}
shinyApp(ui = ui, server = server)