在 shinydashboard 中动态创建可排序的 menuSubItems

Dynamically create sortable menuSubItems in shinydashboard

我有一个使用 shinydashboard 包的 Shiny 应用程序,我在其中动态地在 dashboardSidebarsidebarMenu 中创建 menuSubItems。子项的创建由 actionButton 触发。我可以在服务器端很好地创建 menuSubItems,但我还想使用 sortable 包和 sortable_js 函数使它们可排序。不过,我似乎无法弄清楚将 sortable_js 函数放在哪里才能使它真正起作用。

这是我的 MRE:

library(shiny)
library(shinydashboard)
library(sortable)

# Define UI for shinydashboard
ui <- dashboardPage(
    dashboardHeader(),
    dashboardSidebar(
      sidebarMenu(
        menuItem("tab_one", tabName = "test_body"),
        menuItemOutput("test"),
        id = "sidebar"
      )
    ),
    dashboardBody(
      tabItem("test_body",
              actionButton("click_me", "Click Me"))
    )
  )


# Define server logic to dynamically create menuSubItems
server <- function(input, output) {

  observeEvent(input$click_me, {
    tabs_list <-
      lapply(1:5, function(x) {
        menuSubItem(text = paste("tab", x))
      })

    output$test <- renderMenu({
      menuItem("test_tabs", do.call(tagList, tabs_list))
    })
    sortable_js("test_tabs")
  })
}

# Run the application
shinyApp(ui = ui, server = server)

非常感谢任何帮助

sortable_js() 函数生成 HTML,因此需要将其包含在 UI 中。但是,您还必须确保它包含在它适用于已经存在的元素之后;否则它不会工作。在这里,我们可以通过将其作为使用 menuItem():

创建的菜单项的附加子项添加到 renderMenu() 调用的输出中来实现。
output$test <- renderMenu({
  menu <- menuItem("test_tabs", do.call(tagList, tabs_list))
  tagAppendChildren(menu, sortable_js("test_tabs"))
})

现在,您给 sortable_js() 的 ID 必须是您希望其子元素可排序的元素的 CSS ID。在这种情况下,这将是 menuItem() 内的 ul 元素,它包含所有子项。不幸的是,在创建菜单项时无法直接设置此 id,因此我们必须事后注入它。快速检查 menuItem() 源代码会发现 ul 标签是菜单项标签的第二个子标签:

output$test <- renderMenu({
  menu <- menuItem("test_tabs", do.call(tagList, tabs_list))
  menu$children[[2]] <- tagAppendAttributes(menu$children[[2]], id = "test_tabs")
  tagAppendChildren(menu, sortable_js("test_tabs"))
})

通过这些修改,您的示例将会启动 运行:

library(shiny)
library(shinydashboard)
library(sortable)

# Define UI for shinydashboard
ui <- dashboardPage(
  dashboardHeader(),
  dashboardSidebar(
    sidebarMenu(
      menuItem("tab_one", tabName = "test_body"),
      menuItemOutput("test")
    )
  ),
  dashboardBody(
    tabItem("test_body", actionButton("click_me", "Click Me"))
  )
)

# Define server logic to dynamically create menuSubItems
server <- function(input, output) {
  observeEvent(input$click_me, {
    tabs_list <- lapply(1:5, function(x) {
      menuSubItem(text = paste("tab", x))
    })

    output$test <- renderMenu({
      menu <- menuItem("test_tabs", do.call(tagList, tabs_list))
      menu$children[[2]] <- tagAppendAttributes(menu$children[[2]], id = "test_tabs")
      tagAppendChildren(menu, sortable_js("test_tabs"))
    })
  })
}

# Run the application
shinyApp(ui = ui, server = server)

reprex package (v0.3.0)

于 2019-10-16 创建