使用R Shiny的actionButtons将节点添加到树

时间:2016-08-09 08:31:02

标签: r shiny

我正在开发一个Shiny应用程序,用户可以从数据表开始,并根据前面表格的选定过滤器/摘要创建新表格 - 如下所示:

Table1 ---- (filter) > Table2
       ---- (filter) > Table3  ---- (filter) > Table4
                               ---- (filter) > Table5
       ---- (filter) > Table6

使用R中的列表列表,我创建了一个树数据结构(在我的代码示例中称为sliceBox.tree)来跟踪每个表/节点。 每个表都将带有一组输入:一些过滤器设置和一个actionButton,可用于在该父表下创建新的子表。

我正在使用observeEvent()函数来响应每个按钮,但是当我尝试将一个节点附加到observeEvent处理程序内的树时,只会对函数内的复制树进行更改,并且原始树不受影响。有没有办法从observeEvent处理程序内部编辑原始树,或者可能采用不同的方法来执行此操作?

以下是我的代码的精简版本,以说明问题 - 我希望当前代码通过单击任何现有按钮在页面上创建子actionButtons。

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)

真的希望有人可以提供帮助,我一直在广泛搜索,但没有发现任何类似的例子 - 已经坚持了好几天了!

1 个答案:

答案 0 :(得分:1)

解决此问题的一种方法是将树存储在reactiveValues结构中。

# sliceBox.tree <- list(rootNode)
# Use this instead:
sliceBox.tree <- reactiveValues(tree=list(rootNode))

从那时起,将每sliceBox.tree更改为sliceBox.tree$tree。 它对我有用。