4

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)
Walker Harrison
  • 527
  • 3
  • 12
  • You don't need the `numericInput` if you run `Shiny.setInputValue`. – Stéphane Laurent Apr 30 '19 at 08:25
  • what exactly do you use these hidden inputs for? If you want to have dynamic values that are not visible on the ui (and can trigger events), `reactiveValues()` come to mind,... – Tonio Liebrand Apr 30 '19 at 09:37
  • @BigDataScientist the inputs turn on certain visualization options. can `reactiveValues` be accessed/changed via `Shiny.setInputValue` as well? Or are they a different class entirely? – Walker Harrison Apr 30 '19 at 17:00
  • again, i think it would be good to show what your final goal is. `shiny.setInputValue` is a tool and i dont see why one would need it when using reactiveValues,... – Tonio Liebrand Apr 30 '19 at 17:49
  • 1
    To you're related question: You dont need `Shiny.getInputValue`, you can just use `INPUT.value`. – SeGa May 02 '19 at 10:24

0 Answers0