如何从模块内的 modalDialog 动态生成和捕获用户输入?
Posted
技术标签:
【中文标题】如何从模块内的 modalDialog 动态生成和捕获用户输入?【英文标题】:How to dynamically generate and capture user input from modalDialog within a module? 【发布时间】:2021-12-05 15:29:57 【问题描述】:背景:我正在创建捐赠者/样本注册申请。工作流程是这样的:
用户选择捐赠者/样品来自哪个供应商。
用户上传文件(使用datamods::import_file_server()
)。
对该文件运行一些验证(即x
行数、y
列数等,使用datamods::validation_server()
)
选择预先存在的或创建新的字段映射。
4a) 字段映射是用户映射上传的一种机制 文件列到我们的数据库表列。
4b) 如果新建,一个modalDialog
窗口应该会弹出,显示一个 2
列数据表,一列文件列名,一列
selectInput()
填充有我们的数据库表字段
(列)。
我的设置方式是 registration_module
处理 1-3,然后在其中,我有一个嵌套的 fieldmapping_module
作为输入:
-
(已验证的)文件数据
供应商选择
和数据库列
问题:我似乎无法让动态生成的selectInput()
对 Shiny “可见”。下面是fieldmapping_module
代码。
### FieldMapping module ####
fieldmappingUI <- function(id)
tagList(
div(
column(8,
selectInput(
inputId = NS(id, "fieldmapping_selection"),
label = "Select Field Mapping",
choices = c("Choice 1", "Choice 2", "Choice 3")
),
),
column(4,
shinyWidgets::actionBttn(
inputId = NS(id, "create_new_fieldmapping_btn"),
label = "Create New",
icon = icon("file-alt"),
size = "sm"
)
),
style = "display:inline-block",
class = "form-group shiny-input-container")
)
fieldmappingServer <- function(id, file_data, vendor_selection, db_cols)
stopifnot(is.reactive(file_data))
stopifnot(is.reactive(vendor_selection))
moduleServer(id, function(input, output, session)
ns <- session$ns
#observe for creation of new FieldMappings
observeEvent(input$create_new_fieldmapping_btn,
fieldmapping_table <- data.frame(
"File Columns" = colnames(file_data()),
"DB Field Mapping" = rep("", ncol(file_data()))
)
#browser()
for(i in seq_len(nrow(fieldmapping_table)))
fieldmapping_table[i,"DB.Field.Mapping"] <- as.character(selectInput(
inputId = glue::glue("fieldmap_select_fieldmapping_table$File.Column[i]"),
label = NULL,
choices = db_cols
))
#browser()
#display the table
showModal(modalDialog(
renderDataTable(
DT::datatable(fieldmapping_table,
escape = 2,
selection = "none",
filter = 'none',
options = list(
dom = 't'
),
callback = JS("table.rows().every(function(i, tab, row)
var $this = $(this.node());
$this.attr('id', this.data()[0]);
$this.addClass('shiny-input-slider-input');
);
Shiny.unbindAll(table.table().node());
Shiny.bindAll(table.table().node());")
)
),
title = "New Field Mapping",
footer = tagList(
actionButton(ns("submit_fieldmapping"), label = "Submit", icon = icon("paper-plane")),
modalButton(label = "Close", icon = icon("window-close"))
)
))
)
observeEvent(input$submit_fieldmapping,
browser()
)
)
异常行为:例如,假设我上传了一个包含 3 列的文件:Subject_ID
、Col_A
和 Col_B
,并且它已通过验证(在 @987654340 中完成) @,未显示)。
当我点击modalDialog
的提交按钮时,应用程序由于browser()
调用而暂停,我只能访问input$fieldmap_select_[column name]
(例如:input$fieldmap_select_Subject_ID
),但我没有'吨。我认为自定义 JS 回调可以实现这一点,因为它似乎已经工作了here(以及我在谷歌搜索时遇到的其他代码/应用程序)。
在browser()
暂停时,如果我在控制台中输入input
以查看输入列表,我确实看到了我创建的动态生成的输入(前三个),但它们都是NULL
,尽管在 modalDialog 窗口中“设置”了它们。
我不太精通 javascript/Shiny 交互,但如果我能得到任何帮助,我将不胜感激!我做错了什么?
(交叉发布在RStudio community forum)
【问题讨论】:
【参考方案1】:想通了。我需要在输入字段的动态生成中包含服务器端 ns
函数。即:
for(i in seq_len(nrow(fieldmapping_table)))
fieldmapping_table[i,"DB.Field.Mapping"] <- as.character(selectInput(
inputId = ns(glue::glue("fieldmap_select_fieldmapping_table$File.Column[i]")),
label = NULL,
choices = db_cols
))
注意ns()
周围的inputId
调用。
【讨论】:
以上是关于如何从模块内的 modalDialog 动态生成和捕获用户输入?的主要内容,如果未能解决你的问题,请参考以下文章
如何在dojo Modaldialog中单击关闭按钮来捕获事件?
在 Elixir 或 Erlang 中,如何在运行时动态创建和加载模块?
如何在Elixir或Erlang中在运行时动态创建和加载模块?