3

I am using assign in for loop to create new variables that I want to use in more than one outputs in shiny ui. Following is a sample code:

library(shiny)
ui <- fluidPage(

  mainPanel(fluidRow(textOutput("a")),
            fluidRow(textOutput("b")))
)
server <- function(input, output) {

  m <- reactive({1:5})

  output$a <- renderPrint({

    for (i in 1:length(m())){
      assign(paste0("h",i), "u")
      }

    list(h1,h2)
  })

  output$b <- renderPrint({

   list(h1,h2)
  })
}
shinyApp(ui = ui, server = server)

Problem

Each output in server has its own environment. So, the variables h1 to h5 are created within output a and therefore not accessible by output b. See the result of running app:

[[1]] [1] "u" [[2]] [1] "u"
[[1]] function (...) tags$h1(...) <environment: namespace:htmltools> [[2]] function (...) tags$h2(...) <environment: namespace:htmltools>

Ideally, the second line should be same as the first line. If I move the for loop to server, there is a problem of reactivity:

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.)

Question

How can I make the for loop reactive so that all the outputs could access them?

EDIT

I have also tried doing following outside outputs:

observe({for (i in 1:length(m())){
    assign(paste0("om",i), "u")
  }})

and

reactive({for (i in 1:length(m())){
    assign(paste0("om",i), "u")
  }})

Since h1 is already a function in shiny, I changed the object name to "om". But using either of the above yields no good results:

output$a <- renderPrint({


    list(length(m()), om1)

  })

  output$b <- renderPrint({

   om1()
  })

Error: object 'om1' not found
Error: could not find function "om1"
umair durrani
  • 5,597
  • 8
  • 45
  • 85
  • Why not run `for loop` outside output functions then pass the assign h's in both `renderPrint()`. Just like any [function](http://www.statmethods.net/management/userfunctions.html) apart from shiny, processing within one is limited to function`s scope unless return is used. – Parfait Sep 03 '15 at 03:41
  • @Parfait Sorry, I didn't understand your comment. Can you provide any example for my code? – umair durrani Sep 03 '15 at 03:46

1 Answers1

2

As I tried to relay in the comment, move the for loop outside the first renderPrint() function, so the h1-h5 is available for both output$a and output$b.

From your code there is no reason the loop needs to be restricted to only output$a as its parameter m is defined outside anyway:

library(shiny)
ui <- fluidPage(

  mainPanel(fluidRow(textOutput("a")),
            fluidRow(textOutput("b")))
)
server <- function(input, output) {

  m <- reactive({1:5})

  for (i in 1:length(m)){
      assign(paste0("h",i), "u")
  }

  output$a <- renderPrint({

    list(h1,h2)
  })

  output$b <- renderPrint({

   list(h1,h2)
  })
}
shinyApp(ui = ui, server = server)
Parfait
  • 104,375
  • 17
  • 94
  • 125
  • 1
    This doesn't work. I mentioned this in my question that doing so results in problem in reactivity: `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.)` – umair durrani Sep 03 '15 at 15:41
  • 2
    See edit. Try `m` alone in `for loop`, not `m()` since `m` is not a defined function. Just ran it on my end and all h's are read in both outputs. Even tried h3 and h5. – Parfait Sep 04 '15 at 01:22
  • Now, om1 prints correctly in both `output`s. But om2 to om5 do not. `Error in func() : object 'om3' not found`. I've replaced h to om since h1-h5 represent heading styles in `shiny`. – umair durrani Sep 04 '15 at 02:45