Hello everyone, this is my first post on this forum
I am having a problem with designing a shiny application - in summary, I would like my app to be a annotation tool - it downloads some textual data from DB. A user is presented with this data, and can add an annotation to the data - it then gets added to DB, and user is presented with status of addition (it could fail, so this outcome needs to be presented).
My biggest problem is that I don't know how to approach dynamically creating and assigning observeEvents, and then managing them. In case the user selected different set of filters, I have no idea on how to remove existing observeEvents - since they are dumped in server's body, and are not assigned to any value that could be removed/updated.
My app looks like this:
library(shiny)
library(dplyr)
library(tibble)
library(purrr)
dt <- tribble(
~ID, ~Content, ~Note,
'AB', 'Lorem ipsum', NA_character_,
'BC', 'dolor sit amet', NA_character_,
'CD', 'consectetur adipiscing', NA_character_,
'DE', 'sed do eiusmod', NA_character_,
'EF', 'tempor incididunt', NA_character_,
'FG', 'ut labore et dolore', NA_character_
)
# Simulate a 50% change of failure.
simulateInsert <- function() {
ifelse(runif(1) < .5, TRUE, FALSE)
}
ui <- fluidPage(
titlePanel("Dynamic Buttons"),
sidebarLayout(
sidebarPanel(
sliderInput("buttons",
"Number of buttons:",
min = 3,
max = 6,
value = 4),
uiOutput('dynamicButtons')
),
mainPanel(
uiOutput('mainUI')
)
)
)
server <- function(input, output) {
comm <- reactiveValues(
data = NULL
)
# Simulate data download and filtering
observeEvent(input$buttons,
{
comm$data <- dt[1:input$buttons, ]
})
# Buttons and textInput creation part
mainUI <- reactive({
req(comm$data)
ids <- isolate(comm$data$ID)
print(ids)
imap(ids,
function(x, y)
{
output[[paste0('content', y)]] <- renderText(as.character(y))
output[[paste0('result', y)]] <- renderText('')
fluidRow(
textOutput(paste0('content', y)),
textInput(paste0('txt', y), paste0('Text Input ', x)),
actionButton(paste0('but', y), paste0('Send', x)),
textOutput(paste0('result', y))
)
}
)
})
output$mainUI <- renderUI({
mainUI()
})
observeEvent(mainUI(),
{
req(mainUI())
imap(comm$data,
function(x, y)
{
observeEvent(input[[paste0('but', y)]],
{
print('Executing')
if(simulateInsert() == TRUE) {
output[[paste0('result', y)]] <- 'Success'
} else{
output[[paste0('result', y)]] <- 'Failed'
}
})
})
})
}
# Run the application
shinyApp(ui = ui, server = server)
The last observe does not work as expected - it never executes.
I have also considered a possibility of using:
observeEvent(input[[grepl("but", names(input))]],
{
## Do... something that hmmmm... ?
}
)
But does not work because of error below. Even if it worked I am not sure how shall I sort out which button has been pressed (probably using an intermediate reactiveValues object)
Warning: Error in checkName: Must use single string to index into reactivevalues
62: stop
61: checkName
60: [[.reactivevalues
58: observeEventExpr
1: runApp
Is there a way to do what I want that I am missing? Any suggestion is very welcome!