I'm working on a Shiny app where users can start from a table of data, and create new tables based on selected filters/summaries of the previous tables - something like this:
Table1 ---- (filter) > Table2
---- (filter) > Table3 ---- (filter) > Table4
---- (filter) > Table5
---- (filter) > Table6
Using lists of lists in R, I made a tree data structure (called sliceBox.tree in my code example) to keep track of each table/node. Each table will come with a set of inputs as well: some filter settings and an actionButton, which can be used to create a new child table under that parent table.
I'm using the observeEvent() function to react to each button press, but when I try to append a node to the tree inside the observeEvent handler, the changes are only made to the copy tree inside the function, and the original tree is unaffected. Is there a way to edit the original tree from inside the observeEvent handler or maybe a different approach to do this?
Here is a trimmed-down version of my code now to illustrate the problem - I want the current code to create child actionButtons on the page by clicking on any existing buttons.
server <- function(input, output) {
newNode <- function(id, parentId) {
node <- list(
parent = parentId,
children = list(),
uiObject = createButton(id, parentId)
)
return(node)
}
createButton <- function(id, parentId) {
print(paste0("Creating button ", id))
buttonID <- paste0("sliceBoxButton", id)
return(actionButton(buttonID, paste0("I am ", buttonID, ", child of ", parentId), icon("plus-circle fa-2x")))
}
rootNode <- newNode(1, 0)
sliceBox.tree <- list(rootNode) # We'll store our nodes as a 1D list, so parent and child ID's are recorded as their indices in the list
output$debug <- renderPrint({
print(paste0("Button presses: ", v$counter))
print("FULL TREE")
print(sliceBox.tree)
})
# Keep a total count of all the button presses (also used loosely as the number of tables created)
v <- reactiveValues(counter = 1L)
# Event handlers: specific function for particular button will run when that button is pressed
observeEvent(v$counter, {
for (id in 1:v$counter) {
buttonID <- paste0("sliceBoxButton", id)
observeEvent(input[[buttonID]], {
v$counter <- v$counter + 1L
print(paste0("Pressed ", buttonID))
# Append new child to list of children
numChildren <- length(sliceBox.tree[[id]]$children)
sliceBox.tree[[id]]$children[numChildren + 1] <- v$counter
sliceBox.tree[[v$counter]] <- newNode(v$counter, id)
print(paste0("Appending node to tree at index ", v$counter))
print(sliceBox.tree)
})
}
})
# renderUI needs a list of uiObjects, so we just extract the uiObjects from every node of the tree
output$allSliceBoxes <- renderUI({
table_output_list <- lapply(1:v$counter, function(i) {
return(getElement(sliceBox.tree[[i]], 'uiObject'))
})
do.call(tagList, table_output_list) # Convert the list to a tagList
})
}
ui <- fluidPage(
uiOutput("allSliceBoxes"),
verbatimTextOutput('debug')
)
shinyApp(ui = ui, server = server)
Really hope someone can help, I've been googling extensively but haven't found any examples that do something similar - been stuck on this for days!