0

I would like to use do.call to run render family functions, like renderPrint(). Below code doesn't work:

rm(list=ls())

library(shiny)

ui <- fluidPage(

  selectInput("select", label = h3("Select box"), 
              choices = list("Choice 1" = 1, "Choice 2" = 2, "Choice 3" = 3), 
              selected = 1),
  hr(),
  fluidRow(column(3, verbatimTextOutput("value")))

)

server <- function(input, output, session) {

  output$value <- do.call("renderPrint", list({ input$select }))
}

shinyApp(ui, server)

Error:

Warning: Error in .getReactiveEnvironment()$currentContext: Operation not allowed without an active reactive context. (You tried to do something that can only be done from inside a reactive expression or observer.)
Stack trace (innermost first):
    45: .getReactiveEnvironment()$currentContext
    44: .subset2(x, "impl")$get
    43: $.reactivevalues
[...]

How to achieve this? I am guessing that this is somehow connected with environment and lazy evaluation, so closure might the solution, but this is only guessing...

RSzT
  • 307
  • 3
  • 14
  • I suspect `observe({ output$value <- do.call("renderPrint", list({ input$select })) }) would resolve the issue. – Benjamin Oct 11 '17 at 01:46

2 Answers2

0

I found a way to archieve this based on this answer from SO. The key part is using alist instead of list. From the documentation:

alist handles its arguments as if they described function arguments. So the values are not evaluated, and tagged arguments with no value are allowed whereas list simply ignores them. alist is most often used in conjunction with formals.

rm(list=ls())

library(shiny)

ui <- fluidPage(    
  selectInput("select", label = h3("Select box"), 
              choices = list("Choice 1" = 1, "Choice 2" = 2, "Choice 3" = 3), 
              selected = 1),
  hr(),
  fluidRow(column(3, verbatimTextOutput("value")))    
)

server <- function(input, output, session) {          
  output$value <- do.call(
    renderPrint, 
    alist(input$select)
  )
}

shinyApp(ui, server)

Alternatively, you can probably use the quoted argument in renderPrint and wrap quote around your expressions, but I had no luck with that approach.

Gregor de Cillia
  • 7,397
  • 1
  • 26
  • 43
0

note: I was trying to add on to Gregor's answer in a comment but kind of failed.. read his first!

do.call evaluates its arguments by default when it constructs the call.

But you can specify quote = TRUE to leave the args unevaluated:

output$value <- do.call(renderPrint, list(quote(input$select), quoted = TRUE), quote = TRUE)

But simpler would be to just use a quoted arg with the call:

output$value <- do.call(renderPrint, list(quote(input$select)))

Then the quoted expression gets evaluated at the time of the call, and you won't be evaluating input$select outside a reactive context.

greg L
  • 4,034
  • 1
  • 19
  • 18
  • `alist` does a trick and it is simpler modification than `quote`, but thx for answer. – RSzT Oct 11 '17 at 08:46
  • Very interesting. I was actually playing around with `quote` quite a bit and couldn't make it work. Seeing that it is so straightforward makes me fell a little dumb :) – Gregor de Cillia Oct 11 '17 at 14:12