Nel*_*ieG 3 user-interface module r shiny shiny-reactivity
我试图允许用户从另一个模块(ui_module1)添加在server_module2中看到的连续 UI 输出。因此,当他们点击按钮时,他们将看到 3 个 UI 对象:textOutput、sliderInput、textInput。我下面的代码在输出 UI 对象时停止。如果我不将它包装在第一个模块中,它就可以正常工作。
谢谢。
library(shiny)
library(shinydashboard)
library(shinydashboardPlus)
library(shinyWidgets)
library(dplyr)
ui_module2 = function(id) {
ns = NS(id)
uiOutput(ns("finalOut"))
}
server_module2 = function(id) {
moduleServer(id,
function(input, output, session) {
output$finalOut = renderUI({
ns = session$ns
textOutput(p(style = "color: red", paste0("Package Num:", id, sep = "-")))
sliderInput("n", "N", 1, 1000, 500)
textInput("label", "Label")
})
})
}
ui_module1 = function(id) {
ns = NS(id)
actionBttn(ns("actionbutton1"), "Press Button For New UI")
}
server_module1 = function(id) {
moduleServer(id,
function(input, output, session) {
observeEvent(input$actionbutton1, {
i = sprintf('%04d', input$actionbutton1)
id = sprintf('static%s', i)
print(id)
insertUI(selector = "#actionbutton1",
where = "afterEnd",
ui = ui_module2(id))
server_module2(id)
})
})
}
ui = fluidPage(ui_module1("opt)"))
server = function(input, output, session) {
server_module1("opt)")
}
shinyApp(ui, server)
Run Code Online (Sandbox Code Playgroud)
这是工作代码。很多事情你需要注意。以下是一些要点。
ns。renderUI只返回一个对象,如果要返回多个组件,请使用tagList或div。insertUI模块内的选择器还需要添加ns.自己检查代码是否有小错误。
library(shiny)
library(shinydashboard)
library(shinydashboardPlus)
library(shinyWidgets)
library(dplyr)
ui_module2 = function(id) {
ns = NS(id)
uiOutput(ns("finalOut"))
}
server_module2 = function(id) {
moduleServer(id,
function(input, output, session) {
output$finalOut = renderUI({
ns = session$ns
div(
# not sure what you want with next line, commented, fix your own
# textOutput(p(style = "color: red", paste0("Package Num:", id, sep = "-"))),
sliderInput(ns("n"), "N", 1, 1000, 500),
textInput(ns("label"), "Label")
)
})
})
}
ui_module1 = function(id) {
ns = NS(id)
actionBttn(ns("actionbutton1"), "Press Button For New UI")
}
server_module1 = function(id) {
moduleServer(id,
function(input, output, session) {
ns <- session$ns
observeEvent(input$actionbutton1, {
i = sprintf('%04d', input$actionbutton1)
id = sprintf('static%s', i)
print(id)
insertUI(selector = paste0("#", ns("actionbutton1")),
where = "afterEnd",
immediate = TRUE,
ui = ui_module2(ns(id)))
server_module2(id)
})
})
}
ui = fluidPage(ui_module1("opt"))
server = function(input, output, session) {
server_module1("opt")
}
shinyApp(ui, server)
Run Code Online (Sandbox Code Playgroud)
本例是嵌套模块的示例。要理解这一点,您需要了解ns命名空间在 Shiny 中的工作原理。正如Shiny的官方文档,他们告诉你需要ns(id)在模块UI上添加,而模块服务器不需要这样做,但他们没有告诉你为什么。
当您调用 时moduleServer(id, function(input, output, session) {...}),此处的会话与您的顶级会话不同。如果你检查这里的会话,它是一个session_proxy类对象,不再是ShinySession类对象。moduleServer这就是shiny内部如何知道模块内部的表达式的方式。当调用模块作用域下的input, output, renderXX,updateXX方法时,会先查询session对象,如果是session_proxy,则session$ns先调用 附加命名空间。这就是为什么你不需要ns()在服务器上添加,shiny 已经帮你做了。
好吧,让我们回到嵌套模块问题。让我们通过这个简单的例子来看看 UI 和服务器上的命名空间是什么。它所做的只是打印出 UI 和服务器上的名称空间。
library(shiny)
uiMod2 <- function(id) {
ns <- NS(id)
div(id = ns(""))
}
serverMod2 <- function(id) {
moduleServer(
id,
function(input, output, session) {
ns <- session$ns
print(ns(""))
})
}
uiMod1 <- function(id) {
ns <- NS(id)
tagList(
div(id = ns("")),
uiMod2(ns("level2"))
)
}
serverMod1 <- function(id) {
moduleServer(
id,
function(input, output, session) {
ns <- session$ns
print(ns(""))
serverMod2("level2")
})
}
ui <- fluidPage(uiMod1("level1"))
server <- function(input, output, session) {serverMod1("level1")}
shinyApp(ui, server)
Run Code Online (Sandbox Code Playgroud)
结果用户界面
服务器
[1] "level1-"
[1] "level1-level2-"
Run Code Online (Sandbox Code Playgroud)
看到不同?我没有调用ns二级服务器,只是调用了serverMod2("level2"),但是命名空间会自动为我附加。然而,shiny 不知道将其应用到 UI,所以我必须使用uiMod2(ns("level2")).
闪亮之所以不知道,是因为session。当您创建模块时,您需要传递function(input, output, session),并且当您创建嵌套模块时,session第二级模块的 this 不是ShinySession,而是session_proxy,因此父命名空间将自动附加。
UI 的情况有所不同。通常,当您创建像这样的模块 UI 时uiMod2 <- function(id) ...,您不会传递会话对象,因此它不知道要继承哪个名称空间。