Execute R code after renderUI()

493 views
Skip to first unread message

Jonathan Keane

unread,
Oct 25, 2015, 12:26:39 AM10/25/15
to Shiny - Web Framework for R
I've been struggling to find a way to ensure that a piece of long running code is executed after a particular user interface is rendered. 

I know this use is not quite what shiny was designed for, but I'm developing a survey-like interface that has a sequence of pages with user inputs on each one. What I would like is that after one specific set of UI elements is displayed, I would like a (sometimes long-running) segment of code to run, but only after the UI has renedred, and with a progress indicator, so that users can be inputting what they need to while the code is running. 

I have gotten this to work, but currently it involves a (very hacky!) use of a custom message to the client:

output$page <- renderUI({
  div
([shiny tags])
})


session$onFlushed
(function() {
  session$sendCustomMessage
(type="grabStimuliList", list(TRUE))
})

I have the message handler:

Shiny.addCustomMessageHandler('grabStimuliList',
function(params){
console
.log(params);
Shiny.onInputChange("grabStims", 1);
});



And above this, I have an observe event that acts 

observeEvent(input$grabStims, {
   
if(input$grabStims==1){
      progress
<- shiny::Progress$new()
      progress$set
(message = "Generating videos", value = 0)
     
[long running R code, with progress updating mechanisms]
   
}
 
})  


This does work, but it feels really hacky and wrong to me. Is there a better way to do this? I've tried putting the long running code along with the progress mechanism in the session$onFlushed({...}) directly, but that gives me the error:

Error in public_bind_env$initialize(...) :
 
'session' is not a ShinySession object.

It will run if I remove the progress code, but then there's no indication to the user of the progress.

I've attached a minimal (non)working example.

Is there anyway to use the progress object inside of session$onFlushed({...})? Thanks.

minimalEx.R

Joe Cheng

unread,
Oct 26, 2015, 1:35:31 PM10/26/15
to Jonathan Keane, Shiny - Web Framework for R
You almost had it. Progress$new() takes three arguments: session, min, and max. If you pass the session explicitly, it works.

You should also pass once=TRUE to session$onFlushed. Otherwise that same code will be executed every time some reactivity is triggered.


--
You received this message because you are subscribed to the Google Groups "Shiny - Web Framework for R" group.
To unsubscribe from this group and stop receiving emails from it, send an email to shiny-discus...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/shiny-discuss/2385d835-4737-4c7e-bdb8-c10a731e1f38%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Jonathan Keane

unread,
Oct 27, 2015, 2:34:59 PM10/27/15
to Shiny - Web Framework for R
Thank you, Joe, that is *exactly* what I was missing. After adding session I was getting the behavior I was hoping for. Although I did run into what I think might be a bug of sorts (or at least something I couldn't find documentation on...)

If the second screen has a `selectInput(...)` element in it using the default `selectize=TRUE`, those second elements do not get displayed until after the long running computation (and the progress updating doesn't display either). Everything works as I expect if I use `selectize=FALSE`. For my purposes, I don't need selectize, so it's not a big deal, but I was surprised that that alone would change the rendering behavior. Again, I've attached a minimal working example, line 30 has the relevant element.

Thank you, again, for the quick and clear reply.

-Jon
minimalEx.R

Joe Cheng

unread,
Oct 27, 2015, 5:43:35 PM10/27/15
to Jonathan Keane, Shiny - Web Framework for R
It is a weird quirk. The problem is that using a selectize input on the second page causes the browser to try to load the JavaScript for selectize from the browser at that time. It loads it in a way that causes the entire browser to block waiting for the JavaScript to be downloaded. But the server is too busy executing your long running task to respond to the download request for the JavaScript file. So the browser is blocked and the server is blocked, and nothing can continue on either side until the server is done executing the long running task. The progress messages are actually being sent to the browser, but the browser isn't paying attention because it's still waiting for the JavaScript.

You can see that this is the case by putting a second selectize input on the first page. This will cause the JavaScript to be loaded right off the bat, and Shiny is smart enough not to load it again when the second page loads.



--
You received this message because you are subscribed to the Google Groups "Shiny - Web Framework for R" group.
To unsubscribe from this group and stop receiving emails from it, send an email to shiny-discus...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages