Reputation: 12385
Reproducable example:
server.R
library(shiny)
shinyServer( function(input, output, session) {
myDf <- reactiveValues(myData = NULL)
problematicDf <- reactiveValues(test = NULL)
observeEvent(input$myButton, {
myDf$myData <- df
})
observe({
output$myTestUi <- renderUI({
selectInput(inputId = 'mySelection',
label = 'Selection',
choices = levels(myDf$myData$z),
multiple = T,
selected = c(levels(myDf$myData$z)[1])
)
})
})
observe({
problematicDf$test <- subset(myDf$myData, ((myDf$myData$z %in% input$mySelection)))
})
observe({
str(problematicDf$test)
})
observe({
as.matrix(x = problematicDf$test)
})
})
ui.R
library(shiny)
shinyUI( bootstrapPage(
h3("Push the button"),
actionButton(inputId = "myButton",
label = "clickMe"),
h4("Split Merkmal"),
uiOutput("myTestUi")
))
global.R
df <- data.frame(x = 1:10, y = 10:1, z = letters[1:10])
df$z <- as.factor(df$z)
This gives me:
NULL
[1] "NULL"
NULL
Warning: Unhandled error in observer: 'data' must be of a vector type, was 'NULL'
observe({
as.matrix(x = problematicDf$test)
})
Only looking at the output of
observe({
str(problematicDf$test)
print(class(problematicDf$test))
print(problematicDf$test$z)
})
after clicking on the action Button
, without the as.matrix
, I get:
NULL
[1] "NULL"
NULL
'data.frame': 0 obs. of 3 variables:
$ x: int
$ y: int
$ z: Factor w/ 10 levels "a","b","c","d",..:
[1] "data.frame"
factor(0)
Levels: a b c d e f g h i j
'data.frame': 1 obs. of 3 variables:
$ x: int 1
$ y: int 10
$ z: Factor w/ 10 levels "a","b","c","d",..: 1
[1] "data.frame"
[1] a
Levels: a b c d e f g h i j
That is problematic. As you can see it creates first a df
which is sort of empty, with placeholders, of class = NULL
. And then, it fills this. However, it seems that other reactive functions
, waiting for the problematicDf$test
to be created kick in as soon as the empty df
is created (with class = NULL
). They do not update afterwards anymore. They only update when another selection is made.
This causes (in my case) the program to crash since I need to keep on working and subsetting etc. with the so created data.frame
.
How to handle this?!
I could include an if else
and check for class = NULL
. But it seems to me that this is an unelegant way.
Upvotes: 1
Views: 1707
Reputation: 1933
Is there a reason for you to initialize myDf
as NULL
? If not, you could easily solve your problem assigning df
at it's initialization. If you do so, your code won't need the button either.
And you shouldn't declare your renderUI
inside observe
. Whenever you chance the selected item, the observe
is activated and it will set your selectInput to it's initial state (with only item 'a' selected).
Edit 1
# server.R
shinyServer( function(input, output, session) {
# initialize myDf$myData with df and problematicDf as NULL
myDf <- reactiveValues(myData = df)
problematicDf <- reactiveValues(test = NULL)
# you don't have to observe here. once the selectInput
# has been created, you can (un)select how many choices you want
output$myTestUi <- renderUI({
selectInput(inputId = 'myTestUi',
label = 'Selection',
choices = levels(myDf$myData$z),
multiple = T,
# this line determines that ONLY the first item on
# c(levels(myDf$myData$z)[1] is selected on the selectInput initialization!
selected = c(levels(myDf$myData$z)[1])
)
})
observe({
problematicDf$test <- subset(myDf$myData,
(myDf$myData$z %in% input$myTestUi))
})
observeEvent(input$myButton, {
# the code in here will only run when the button is pushed!
print("you should only put things here that you want to be flushed on the button being clicked!")
})
})
Edit 2
So do initialize myDf$myData
as NULL
and assign df inside the observeEvent
.
The renderUI
will begin as a selectInput
without any choices, but as soon as the button is pushed, choices will be assigned to it.
You mention some reactive
functions that crash when the data is still NULL
. There are lots of ways to deal with that. One way is to just use a if(is.null(myDf$myData)) return(NULL)
as you mentioned. Might not be the most elegant way but usually works just fine. Other ways may include isolate
or an observeEvent
(it doesn't react to NULL inputs by default). It depends on how your app work as a whole.
But it seems you haven't fully understood how reactivity and other shiny elements work. Try reading the rstudio articles, specially the 'reactive programming' part (http://shiny.rstudio.com/articles/).
Upvotes: 1