shiny how to refresh the value of the same component with a for loop

,

shiny how to refresh the value of the same component with a for loop

I need a for loop to perform a computationally expensive operation, adding one for each count.

Here's a simple example where when the button is clicked, the loop inside Sys.sleep(1) simulates the computation time and renders the result to textOutput.

But shiny is single-threaded, which causes only the end-of-loop result to be rendered to textOutput.

I know that progressbar is asynchronous to break the single-threaded limit, but I need to use textOutput. How can I override the for loop to refresh textOutput values?

library(shiny)

ui <- fluidPage(
  actionButton("runLoop", "Run Loop"),
  textOutput("output")
)

server <- function(input, output, session) {
  observeEvent(input$runLoop, {
    for (i in 1:5) {
      Sys.sleep(1)
      
      output$output <- renderText({
        paste("Finished iteration", i)
      })
      
    }
  })
}

shinyApp(ui, server)

I tried using later and promises, but it still failed. This example uses later, but the result of the last loop is directly prerendered, not every loop I wanted.

library(shiny)
library(later)

ui <- fluidPage(
  actionButton("runLoop", "Run Loop"),
  textOutput("output")
)

server <- function(input, output, session) {
  observeEvent(input$runLoop, {
    for (i in 1:5) {
      later::later(function() {
        Sys.sleep(1)
        
        output$output <- renderText({
          paste("Finished iteration", i)
        })
      }, i * 2)
    }
  })
}

shinyApp(ui, server)

Please see this related question.

Regarding the scenario you are describing I'd suggest relying on shiny's reactive cycle instead of using a for-loop:

library(shiny)

ui <- fluidPage(
  actionButton("runLoop", "Run Loop"),
  textOutput("output")
)

server <- function(input, output, session) {
  iteration <- reactiveVal(0L)
  
  observeEvent(input$runLoop, {
    iteration(1L)
  })
  
  observe({
    invalidateLater(300L)
    if(isolate(iteration()) < 5L && isolate(iteration()) > 0L){
      Sys.sleep(1L)
      isolate(iteration(iteration()+1L))
    }
  })
  
  output$output <- renderText({
    paste("Finished iteration", iteration())
  })
}

shinyApp(ui, server)

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.