Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

R shiny Observe running Before loading of UI and this causes Null parameters

Tags:

r

shiny

I am running into an issue because observe is being called first before the UI loads.

Here is my ui.R

  sidebarPanel(
    selectInput("Desk", "Desk:" ,  as.matrix(getDesksUI())),
    uiOutput("choose_Product"), #this is dynamically created UI
    uiOutput("choose_File1"), #this is dynamically created UI
    uiOutput("choose_Term1"), #this is dynamically created UI  ....

Here is my Server.R

shinyServer(function(input, output,session) {

  #this is dynamic UI
  output$choose_Product <- renderUI({ 
    selectInput("Product", "Product:", as.list(getProductUI(input$Desk)))
  })

   #this is dynamic UI
  output$choose_File1 <- renderUI({
    selectInput("File1", "File 1:", as.list(getFileUI(input$Desk, input$Product)))
  })

  #this is dynamic UI and I want it to run before the Observe function so the call
  # to getTerm1UI(input$Desk, input$Product, input$File1) has non-null parameters
  output$choose_Term1 <- renderUI({
    print("Rendering UI for TERM")
    print(paste(input$Desk," ", input$Product, " ", input$File1,sep=""))
    selectInput("Term1", "Term:", getTerm1UI(input$Desk, input$Product, input$File1))
  })

This is my observe function and it runs before the input$Product and input$File1 are populated so I get an error because they are both NULL. But I need to use the input from the UI.

   observe({ 
    print("in observe")
    print(input$Product)
    max_plots<-length(getTerm2UI(input$Desk, input$Product, input$File1))
    #max_plots<-5
            # Call renderPlot for each one. Plots are only actually generated when they
            # are visible on the web page.
            for (i in 1:max_plots )   {
              # Need local so that each item gets its own number. Without it, the value
              # of i in the renderPlot() will be the same across all instances, because
              # of when the expression is evaluated.
              local({
               my_i <- i
                plotname <- paste("plot", my_i, sep="")
                output[[plotname]] <- renderPlot({
                  plot(1:my_i, 1:my_i,
                       xlim = c(1, max_plots ),
                       ylim = c(1, max_plots ),
                        main = paste("1:", my_i, ". n is ", input$n, sep = "") )
                })
              })
            }##### End FoR Loop
 },priority = -1000)

Any idea how to get the input$Product and input$File1 to be populated BEFORE observe runs?

Thank you.

like image 221
user3022875 Avatar asked Apr 03 '14 18:04

user3022875


2 Answers

EDIT: Scroll down to TClavelle's answer for a better solution. While this answer has the most upvotes, I wrote it when Shiny had fewer features than it does today.

The simplest way is to add an is.null(input$Product) check at the top of each observe, to prevent it from running before the inputs it uses are initialized.

If you don't want your observers to do the null-check each time they're run, you can also use the suspended = TRUE argument when registering them to prevent them from running; then write a separate observer that performs the check, and when it finds that all inputs are non-null, calls resume() on the suspended observers and suspends itself.

like image 56
Fadeway Avatar answered Nov 11 '22 02:11

Fadeway


You need to use the Shiny Event Handler and use observeEvent instead of observe. It seems to be about the only way to get rid of the "Unhandled error" message caused by NULL values on app startup. This is so because unlike observe the event handler ignores NULL values by default.

So your observe function could end up looking something like this (no need for priorities, or resume/suspended etc!)

observeEvent(input$Product, ({

  max_plots<-length(getTerm2UI(input$Desk, input$Product, input$File1))
  ... (etc)      

  })# end of the function to be executed whenever input$Product changes
 )

I could not copy paste your example code easily to make it run, so I'm not entirely sure what your full observe function would look like.

like image 11
FvD Avatar answered Nov 11 '22 04:11

FvD