【问题标题】:Shiny modules: switch tabs from within modules that have different namespaces闪亮的模块:从具有不同命名空间的模块中切换选项卡
【发布时间】:2021-11-03 20:48:48
【问题描述】:

我有一个带有多个选项卡的闪亮应用程序,我希望在选项卡中包含允许用户切换选项卡的操作按钮。我之前问过这个问题:R Shiny: Change tabs from within a module 并得到了一个有帮助的答案,但并没有完全解决我的问题。

当我使用相同的id(tab.1)调用modtab1和modtab2时,它允许我切换标签,但它不区分两个input$userids;当我使用不同的 id 时,它会区分两个 input$userids,但不允许我切换标签。

library(shiny)
modtab1_ui <- function(id) {
  ns <- NS(id)
  tabPanel(title = 'Tab 1',
           value = NS(id, 'tab.1'),
           h4('This is the first tab'),
           actionButton(NS(id, 'nexttab'), 'Next Tab'),

           textInput(NS(id, 'userid'), 'User ID'),
           textOutput(outputId = NS(id, 'id'))
          ) # tabPanel
}

modtab1_server <- function(id) {
  moduleServer(id,
               function(input, output, session) {
                 observeEvent(input$nexttab, {
                   print(paste('switching to tab 2', input$userid))
                   updateTabsetPanel(session = session, inputId =  'tabs', 
                                     # selected = NS('tab2', 'tab.2')
                                     # selected = 'tab.2'
                                     selected = ns('tab.2')
                                    )
                 })
                 
                 output$id <- renderText(input$userid)
               })
}

modtab2_ui <- function(id) {
  ns <- NS(id)
  tabPanel(title = 'Tab 2',
           value = NS(id, 'tab.2'),

           h4('This is the second tab'),
           actionButton(NS(id, 'firsttab'), 'First Tab'),

           textInput(NS(id, 'userid'), 'User ID'),
           textOutput(outputId = NS(id, 'useridout'))
          ) # tabPanel
}

modtab2_server <- function(id) {
  moduleServer(id,
               function(input, output, session) {
                 observeEvent(input$firsttab, {
                   print(paste('switching to tab 1', input$userid))
                   updateTabsetPanel(session = session, inputId =  'tabs', 
                                     # selected = NS('tab1', 'tab.1')
                                     # selected = 'tab.1'
                                     selected = ns('tab.1')
                                     )
                 })
                 
                 output$id <- renderText(input$userid)
               })
}


ui <- fluidPage(
  tabsetPanel(
    'tabs',
             modtab1_ui('tab1'),
             modtab2_ui('tab2')
  )
)

server <- function(input, output, session) {
  modtab1_server('tab1')
  modtab2_server('tab2')
}

shinyApp(ui = ui, server = server)

【问题讨论】:

  • 您需要让模块服务器函数向主服务器函数返回一个值,然后让主服务器函数根据模块服务器返回的值的更改更新所选选项卡。

标签: r shiny shinymodules


【解决方案1】:

这是一个 MWE,我认为它可以满足您的需求。

library(shiny)

modtab1_ui <- function(id) {
  ns <- NS(id)
  tabPanel(
    title = 'Tab 1',
    value = ns('tab'),
    h4('This is the first tab'),
    actionButton(ns('nexttab'), 'Next Tab')
  ) # tabPanel
}

modtab1_server <- function(id) {
  moduleServer(id,
                  function(input, output, session) {
                    retVal <- reactiveValues(count=0)
                    
                    observeEvent(input$nexttab, retVal$count <- retVal$count + 1)
                    return(reactive(retVal$count))
                 })
}

modtab2_ui <- function(id) {
  ns <- NS(id)
  tabPanel(
    title = 'Tab 2',
    value = ns('tab'),
    h4('This is the second tab'),
    actionButton(ns('firsttab'), 'First Tab')
  ) # tabPanel
}

modtab2_server <- function(id) {
  moduleServer(id,
               function(input, output, session) {
                 retVal <- reactiveValues(count=0)
                 
                 observeEvent(input$firsttab, retVal$count <- retVal$count + 1)
                 return(reactive(retVal$count))
               })
}

ui <- fluidPage(
  tabsetPanel(
   id='tabs',
   modtab1_ui('tab1'),
   modtab2_ui('tab2')
  )
)

server <- function(input, output, session) {
  
  tab1val <- modtab1_server('tab1')
  tab2val <- modtab2_server('tab2')
  
  observeEvent(tab1val(), {
    updateTabsetPanel(session, 'tabs', selected = 'tab2-tab')
  })  
  
  observeEvent(tab2val(), {
    updateTabsetPanel(session, 'tabs', selected = 'tab1-tab')
  })
}

shinyApp(ui = ui, server = server)

注意对语法的更改,尤其是关于 nsNS 的使用以及传递给函数的参数。

另外,请注意模块服务器函数的返回值的使用,以及它们在主服务器函数中的访问方式。

【讨论】:

  • 这行得通,谢谢。我很好奇为什么我需要创建一个 reactiveValues 对象而不仅仅是一个响应式对象?
  • 你不需要。这只是我选择这样做的方式。通常有很多方法可以给 R 猫剥皮。
  • 我明白了。当我尝试响应式对象时它不起作用,但我可能做错了其他事情。无论哪种方式,你的修复工作,所以谢谢你!
【解决方案2】:

以 Limey 的回应为基础。您可以通过 UI 模块的附加形式简化为一个模块。

library(shiny)

modTabUi <- function(id, panelTitle = 'Tab 1', headding = 'This is the first tab', buttonLabel = 'Next Tab') {
  ns <- NS(id)
  tabPanel(
    title = panelTitle,
    value = ns('tab'),
    h4(headding),
    actionButton(ns('nexttab'), buttonLabel)
  )
}

modTabServer <- function(id) {
  moduleServer(id,
               function(input, output, session) {
                 retVal <- reactiveValues(count = 0)
                 
                 observeEvent(input$nexttab, retVal$count <- retVal$count + 1)
                 return(reactive(retVal$count))
               })
}


ui <- fluidPage(
  tabsetPanel(
    id='tabs',
    modTabUi('tab1', panelTitle = 'Tab 1', headding = 'This is the first tab', buttonLabel = 'Next Tab'),
    modTabUi('tab2', panelTitle = 'Tab 2', headding = 'This is the second tab', buttonLabel = 'Back to First Tab')
  )
)

server <- function(input, output, session) {
  
  tab1val <- modTabServer('tab1')
  tab2val <- modTabServer('tab2')
  
  observeEvent(tab1val(), {
    updateTabsetPanel(session, 'tabs', selected = 'tab2-tab')
  })  
  
  observeEvent(tab2val(), {
    updateTabsetPanel(session, 'tabs', selected = 'tab1-tab')
  })
}

shinyApp(ui = ui, server = server)

【讨论】:

  • 是的。我也想过,但是由于 OP 特别提到了 两个 模块......也就是说,这是一个有用的概括。
  • 我的模块已经足够不同了(实际上到过程结束时我至少会有四个),这特别是行不通的,但这确实有助于以这种方式思考它。谢谢!
猜你喜欢
  • 1970-01-01
  • 2017-12-23
  • 2017-12-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-29
  • 1970-01-01
  • 2019-10-22
相关资源
最近更新 更多