如何将Shiny浏览器时区值从UI传递至readTzServer模块并读取
你的问题核心在于模块UI元素没有正确使用命名空间,导致client_time_zone_international这个输入项注册在了全局命名空间下,而模块的server函数只能访问自己命名空间内的输入。另外代码里还有一处语法错误需要修正,下面一步步来解决:
核心问题分析
在readTzUi中,你创建textInput时没有用ns()包裹ID:
textInput("client_time_zone_international", "Time zone international", value = "")
这会让这个输入项的ID直接是client_time_zone_international(全局命名空间),而模块的readTzServer只能访问以模块ID(这里是readtz1)为前缀的命名空间内的输入(比如readtz1-button),所以自然拿不到全局的client_time_zone_international的值,而主server可以访问全局所有输入,所以能打印出值。
同时你的readTzServer里有一处语法错误:count observe({应该是observe({。
修正步骤
1. 给UI元素添加命名空间
把textInput的ID用ns()包裹,让它属于模块的命名空间:
textInput(ns("client_time_zone_international"), "Time zone international", value = "")
2. 调整JS代码适配命名空间
原来的JS选择器$("#client_time_zone_international")现在找不到元素了,因为元素ID变成了readtz1-client_time_zone_international(模块ID+原ID)。更可靠的方式是用Shiny.setInputValue直接给模块内的输入赋值,同时利用Shiny的命名空间机制:
tags$script(sprintf(' $(function() { Shiny.setInputValue("%s", Intl.DateTimeFormat().resolvedOptions().timeZone); }); ', ns("client_time_zone_international")))
这种方式直接用ns()生成正确的ID字符串传入JS,避免手动处理命名空间,更简洁可靠。
3. 修复server里的语法错误
把count observe({改成observe({。
完整修正后的代码
library(shiny) readTzUi <- function(id, label = "readTz"){ ns <- NS(id) fluidPage( # 用sprintf生成带正确命名空间的JS代码 tags$script(sprintf(' $(function() { Shiny.setInputValue("%s", Intl.DateTimeFormat().resolvedOptions().timeZone); }); ', ns("client_time_zone_international"))), # 给textInput添加命名空间 textInput(ns("client_time_zone_international"), "Time zone international", value = ""), tags$br(), actionButton(ns("button"), label = label), verbatimTextOutput(ns("but_out")), verbatimTextOutput(ns("out")) ) } readTzServer <- function(id){ moduleServer( id, function(input, output, session){ # 现在可以正常获取时区值了 observe(print(input$client_time_zone_international)) count <- reactiveVal(0) observeEvent(input$button, { count(count() + 1) }) output$but_out <- renderText({ count() }) # 修复语法错误 observe({ output$out <- renderText({ "Hello" }) }) } ) } ui <- fluidPage( readTzUi("readtz1", "Counter#2") ) server <- function(input, output, session) { readTzServer("readtz1") observe( print(input$client_time_zone_international) ) } shinyApp(ui, server)
验证效果
运行修正后的代码,你会发现readTzServer里的print(input$client_time_zone_international)能正常输出浏览器的时区值,主server也能正常输出,模块的其他功能(按钮计数、文本输出)也能正常工作。
内容的提问来源于stack exchange,提问作者PCdL

