Has anyone come across a solution that would take a list of named items and generate a corresponding set of shiny input fields? With checkboxes where the input class is logical
, etc.
The particular envisioned use case is to -in the context of a run of the mill "render yourR
analysis accessible to non-specialists" project- be able to extract a underlying function's parameters and defaults using formals()
and feed the resulting list (filtered against symbol
s etc.) into the magic functionality outlined above, generating a gui representation of the function interface without the need to manually choose every single element.
Here’s a starting point, but in general there’s just not enough information in function formals to be able to reliably construct inputs.
generate_input_ui <- function(x, id) {
UseMethod("generate_input_ui")
}
generate_input_ui.function <- function(x, id) {
params <- formals(x)
env <- environment(x)
args <- lapply(params, function(param) {
tryCatch(eval(param, env), error = function(e) NULL)
})
shiny::tagList(
Map(generate_input_ui, args, paste0(id, "-", names(args)))
)
}
Add some methods for common types.
generate_input_ui.default <- function(x, id) {
shiny::textInput(id, label = id, value = "")
}
generate_input_ui.logical <- function(x, id) {
shiny::checkboxInput(id, label = id, value = isTRUE(x))
}
generate_input_ui.numeric <- function(x, id) {
shiny::numericInput(id, label = id, value = c(x, 0)[1])
}
generate_input_ui.character <- function(x, id) {
shiny::textInput(id, label = id, value = c(x, "")[1])
}
Try it out.
foo <- function(w, x = TRUE, y = 42, z = "Hello") NULL
generate_input_ui(foo, "foo") |> capture.output() |> cat(sep = "\n")
#> <div class="form-group shiny-input-container">
#> <label class="control-label" id="foo-w-label" for="foo-w">foo-w</label>
#> <input id="foo-w" type="text" class="shiny-input-text form-control" value=""/>
#> </div>
#> <div class="form-group shiny-input-container">
#> <div class="checkbox">
#> <label>
#> <input id="foo-x" type="checkbox" class="shiny-input-checkbox" checked="checked"/>
#> <span>foo-x</span>
#> </label>
#> </div>
#> </div>
#> <div class="form-group shiny-input-container">
#> <label class="control-label" id="foo-y-label" for="foo-y">foo-y</label>
#> <input id="foo-y" type="number" class="shiny-input-number form-control" value="42"/>
#> </div>
#> <div class="form-group shiny-input-container">
#> <label class="control-label" id="foo-z-label" for="foo-z">foo-z</label>
#> <input id="foo-z" type="text" class="shiny-input-text form-control" value="Hello"/>
#> </div>