umair durrani
umair durrani

Reputation: 6147

How to make for loop reactive in shiny server in R?

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"

Upvotes: 3

Views: 2006

Answers (1)

Parfait
Parfait

Reputation: 107567

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)

Upvotes: 2

Related Questions