响应式更新模块化 Shiny 应用程序中的侧边栏

Posted

技术标签:

【中文标题】响应式更新模块化 Shiny 应用程序中的侧边栏【英文标题】:Reactively updating sidebar in modular Shiny app 【发布时间】:2021-03-23 12:01:33 【问题描述】:

我有一个使用bs4Dash 的模块化Golem 应用程序。我想从renderUI 动态生成的actionBttn 更新活动侧边栏选项卡。虽然updatebs4ControlbarMenu 按预期工作as shown here,但它在应用程序的模块化版本中不起作用。我究竟做错了什么?我怀疑它与跨模块的input[[btnID]] 管理有关,但我很难找到解决方案。

没有模块的工作示例as shown here:

library(shiny)
library(shinyWidgets)
library(bs4Dash)
library(tidyverse)

shinyApp(
  ui = bs4DashPage(
    sidebar_collapsed = FALSE,
    controlbar_collapsed = TRUE,
    enable_preloader = FALSE,
    navbar = bs4DashNavbar(skin = "dark"),
    sidebar = bs4DashSidebar(
      inputId = "sidebarState",
      bs4SidebarMenu(
        id = "sidebr",
        bs4SidebarMenuItem(
          "Tab 1",
          tabName = "tab1"
        ),
        bs4SidebarMenuItem(
          "Tab 2",
          tabName = "tab2"
        )
      )
    ),
    
    bs4DashBody(
      bs4TabItems(
        bs4TabItem(
          tabName = "tab1",
          h1("Welcome!"),
          fluidRow(
            pickerInput(
              inputId = "car",
              label = "Car", 
              choices = row.names(mtcars),
              selected = head(row.names(mtcars), 3),
              multiple = TRUE,
              options = list(
                `actions-box` = TRUE)
            ),
            pickerInput(
              inputId = "gear",
              label = "Gear", 
              choices = unique(mtcars$gear),
              selected = unique(mtcars$gear),
              multiple = TRUE,
              options = list(
                `actions-box` = TRUE)
            )
          ),
          
          fluidRow(
            column(6,
                   uiOutput("uiboxes")
            )
          )
        ),
        
        bs4TabItem(
          tabName = "tab2",
          h4("Yuhuuu! You've been directed automatically in Tab 2!")
        )
      )
    )
  ),
  server = function(input, output, session) 
    
    submtcars <- reactive(
      req(input$car, input$gear)
      mtcars %>% 
        mutate(
          carnames = rownames(mtcars)) %>% 
        filter(
          carnames %in% input$car &
            gear %in% input$gear
        )
    )
    
    
    observeEvent( submtcars(), 
      n_ex <- nrow(submtcars())
      output$uiboxes <- renderUI(
        
        lapply(1:n_ex, FUN = function(j) 
          print(paste("j is ", j))
          bs4Box(
            title = submtcars()$carnames[j],
            width = 12,
            str_c("Number of gears:", submtcars()$gear[j]),
            
            btnID <- paste0("btnID", j),
            
            print(btnID),
            fluidRow(
              column(
                2,
                actionBttn(
                  inputId = btnID,
                  icon("search-plus")
                )
              )
            )
          )
        )
      )
      
      lapply(1:n_ex, function(j) 
        btnID <- paste0("btnID", j)
        observeEvent(input[[btnID]] , 
          updatebs4ControlbarMenu(
            session,
            inputId = "sidebr",
            selected = "tab2"
          )
        )
      )
    )
    
  
)

模块化尝试不起作用:

library(shiny)
library(shinyWidgets)
library(bs4Dash)
library(tidyverse)


mod_exlib_ui <- function(id)
  ns <- NS(id)
  tagList(
    fluidRow(
      pickerInput(
        inputId = ns("car"),
        label = "Car", 
        choices = row.names(mtcars),
        selected = head(row.names(mtcars), 3),
        multiple = TRUE,
        options = list(
          `actions-box` = TRUE)
      ),
      pickerInput(
        inputId = ns("gear"),
        label = "Gear", 
        choices = unique(mtcars$gear),
        selected = unique(mtcars$gear),
        multiple = TRUE,
        options = list(
          `actions-box` = TRUE)
      )
    ),
    
    fluidRow(
      column(6,
             uiOutput(ns("uiboxes"))
      )
    )
  )



mod_exlib_server <- function(id)
  moduleServer( id, function(input, output, session)
    ns <- session$ns
    
    submtcars <- reactive(
      # req(input$car, input$gear)
      mtcars %>% 
        dplyr::mutate(
          carnames = rownames(mtcars)) %>% 
        dplyr::filter(
          carnames %in% input$car &
            gear %in% input$gear
        )
    )
    
    
    observeEvent( submtcars(), 
      n_ex <- nrow(submtcars())
      output$uiboxes <- renderUI(
        
        lapply(1:n_ex, FUN = function(j) 
          print(paste("j is ", j))
          bs4Box(
            title = submtcars()$carnames[j],
            width = 12,
            paste("Number of gears: ", submtcars()$gear[j]),
            
            btnID <- paste0("btnID", j),
            
            print(btnID),
            fluidRow(
              column(
                2,
                actionBttn(
                  inputId = ns(btnID),
                  icon("search-plus")
                )
              )
            )
          )
        )
      )
      
      lapply(1:n_ex, function(j) 
        btnID <- paste0("btnID", j)
        observeEvent(input[[btnID]] , 
          print(btnID)
          updatebs4ControlbarMenu(
            session,
            inputId = "sidebr",
            selected = "exdet2"
          )
        )
      )
    )
  )


app_ui <- tagList(
  bs4DashPage(
    navbar = bs4DashNavbar(),
    sidebar = bs4DashSidebar(
      expand_on_hover = TRUE,
      inputId = "sidebarState",
      bs4SidebarMenu(
        id = "sidebr",
        bs4SidebarMenuItem(
          "Tab 1",
          tabName = "tab1"
        ),
        bs4SidebarMenuItem(
          "Tab 2",
          tabName = "tab2"
        )
      )
    ),
    bs4DashBody(
      bs4TabItems(
        bs4TabItem(
          tabName = "tab1",
          h1("Welcome!"),
          mod_exlib_ui("exlib_ui_1")
        ),
        bs4TabItem(
          tabName = "tab2",
          h4("Yuhuuu! You've been directed automatically in Tab 2!")
        )
      )
    )
  )
)

app_server <- function( input, output, session ) 
  # Your application server logic 
  mod_exlib_server("exlib_ui_1")



shinyApp(
  ui = app_ui,
  server = app_server)

【问题讨论】:

【参考方案1】:

探索了同族函数updatebs4TabSetPanel()的例子后,似乎选择的值需要是一个数字。 因此,您可以将此代码与 CRAN 版本 0.5.0 一起使用:

         updatebs4ControlbarMenu(
            session,
            inputId = "sidebr",
            selected = "2" #"exdet2"
          )

【讨论】:

它不起作用。在为updatebs4TabSetPanel() 提供的示例中,selected 不是数字,而是一个字符串(即paste("Tab", input$controller2)):rinterface.github.io/bs4Dash/reference/… input$controller2 是 slideInput 的输出,它是数字的。我使用 CRAN 上的 0.5.0 版。你用的是哪个版本? bs4Dash' 版本 0.6.0.9000。但是,我认为问题与模块以及如何处理 id 更相关?相同的应用程序在未模块化时可以正常工作,如下所示:***.com/a/65241808/7375944 v0.6.0 从未发布过。它将直接从 0.5.0 跳到 2.0,其中有许多重大变化。我建议您回到 CRAN 版本或完全更改为 v2。我向您保证,我的代码修改适用于我这边的 0.5.0。如果你想让我测试你的版本,你必须给我你从 github 下载的版本的提交 SHA1。你可以通过packageDescription("bs4Dash")看到它 GithubSHA1: 5dfbc155d8f32f4d5e0f27aee2740da295f2ffe0

以上是关于响应式更新模块化 Shiny 应用程序中的侧边栏的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 `renderUI` 响应式更新 Shiny 应用程序中的活动菜单项?

「R」Shiny:响应式编程server 函数

更新 bs4dash 版本 2.00 Shiny 中的控制栏

R Shiny DT - 使用反应式编辑表中的值

R Shiny 中的响应式 CSS 属性

「R」Shiny:响应式编程响应式编程