#javascript #r #shiny
Вопрос:
Справочная информация: я создаю приложение для регистрации доноров / образцов. Рабочий процесс как таковой:
- Пользователи выбирают, от какого поставщика исходят доноры / образцы.
- Пользователи загружают файл (используя
datamods::import_file_server()
). - Запустите некоторую проверку для этого файла (т.Е.
x
количество строк,y
количество столбцов и т. Д., Используяdatamods::validation_server()
) - Выберите уже существующее или создайте новое сопоставление полей.
4a) Сопоставление полей — это механизм, позволяющий пользователям сопоставлять столбцы загруженных файлов со столбцами таблицы нашей базы данных.
4b) Если Создать новый,
modalDialog
должно появиться окно, в котором отображаются данные из 2 столбцов, один столбец для имен столбцов файлов, один столбецselectInput()
‘s, которые заполняются полями (столбцами) таблицы нашей базы данных.
Я настроил это таким образом, что a 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
, и он прошел проверку (сделано в registration_module
, не показано).
Когда я нажимаю кнопку отправки modalDialog
, и приложение приостанавливается из-за browser()
вызова, я исключаю, чтобы иметь доступ к input$fieldmap_select_[column name]
(например: input$fieldmap_select_Subject_ID
), но я этого не делаю. Я думал, что пользовательский обратный вызов JS достигнет этого, поскольку, похоже, он сработал здесь (и с другим кодом / приложениями, с которыми я столкнулся во время поиска в Google).
На browser()
паузе, если я вхожу input
в консоль, чтобы просмотреть список входных данных, я действительно вижу созданные мной динамически сгенерированные входные данные (первые три), но они все NULL
, несмотря на то, что они «установлены» в окне ModalDialog.
Я не слишком хорошо разбираюсь во взаимодействии Javascript / Shiny, но был бы признателен за любую помощь, которую я мог бы получить с этим! Что я делаю не так?
(перекрестный пост на форуме сообщества RStudio)
Ответ №1:
Понял это. Мне нужно было включить ns
функцию на стороне сервера в динамическую генерацию полей ввода. ie:
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
.