Background: I am creating a Donor/Sample registration application. The workflow is as such:
- Users select which Vendor the Donors/Samples are from.
- Users upload a file (using
datamods::import_file_server()
). - Run some validation against that file (ie.
x
number of rows,y
number of columns, etc., usingdatamods::validation_server()
) - Select pre-existing or Create a new Field Mapping.
4a) a Field Mapping is a mechanism for users to map the uploaded file columns to our database table columns.
4b) If Create New, amodalDialog
window should pop up, showing a 2 column datatable, one column for File column names, one column ofselectInput()
's that are populated with our database table fields (columns).
I have this set up in such a way that a registration_module
handles 1-3, and then within that, I have a nested fieldmapping_module
which takes as input:
- the (validated) file data
- the vendor selection
- and the database columns
Problem: I cannot seem to make the dynamically generated selectInput()
's "visible" to Shiny. Below is the fieldmapping_module
code.
### 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()
})
})
}
Excepted behavior: For example, say I have uploaded a file with 3 columns: Subject_ID
, Col_A
, and Col_B
, and it has passed validation (done in the registration_module
, not shown).
When I hit the submit button of the modalDialog
, and the app is paused due to the browser()
call, I am excepting to have access to input$fieldmap_select_[column name]
(ex: input$fieldmap_select_Subject_ID
), but I don't. I thought the custom JS callback would achieve this, as it seems to have worked here (and other code/apps I've come across while Googling).
I am not too well versed in Javascript, and how Shiny/JS interact, but would appreciate any help I could get with this! What am I doing wrong?