
Define a data-source placeholder (e.g. upload, database table)
Source:R/paintr-registry.R
ptr_define_placeholder_source.RdA source placeholder produces a data frame the rest of the formula
reads from. Built-in example: ppUpload. Custom examples: database
tables, built-in datasets, URL fetches.
Arguments
- keyword, ui_text_defaults
See
ptr_define_placeholder_value(). Seevignette("ggpaintr-tutorial")§ "Defining your own placeholders" (source role).- build_ui
function(node, label, ...)returning a Shiny tag — same shape as inptr_define_placeholder_value(). Render ONLY the source's data-payload widget atinputId = node$id(e.g. afileInput, aselectInputchooser). Withshortcut = TRUEthe framework emits the sibling shortcuttextInput(atnode$shortcut_id) for you (ADR 0025 item #7) — do NOT render it yourself, or the id would be bound twice. A source whose only entry point is the shortcut (e.g. an env-name loader) may returnNULL.Seeding — same opt-in shape as the other two helpers: declare an optional
selected = NULLformal (or accept...) to receive the seeded value. Seeding is boot-only: aspec=entry naming this source wins on the first render, and on every later render (e.g. a tree rebuild) the user's current pick is authoritative — the spec seed never snaps the widget back. The built-inppUploaddeclines this because a ShinyfileInput()can never be seeded programmatically; custom sources whose primary widget can be seeded (e.g. aselectInputdataset chooser) should accept it.- resolve_data
function(value, node, ...)returning adata.frame(the data downstream consumers read from), orNULLto signal "no data yet". Throw viarlang::abort()for malformed inputs.- resolve_expr
Optional.
function(value, node, ...)returning the expression spliced into the rendered code at the placeholder's position — i.e. how the data is referred to in the reproducible call, not the data itself. Defaultrlang::sym(value)works when the widget's value is already the symbol you want. Override to make the rendered code re-fetch instead of referencing an in-session object, e.g.function(value, node, ...) rlang::ppExpr(read.csv(!!value$datapath)). Withshortcut = TRUE,valuehere is the shortcut input's value (e.g. the typed dataset name), not the primary payload — the built-inppUploadrelies on this so the default splices the typed name as a bare symbol.- shortcut
Single logical (default
FALSE). WhenTRUE, the framework stampsnode$shortcut_id <- paste0(node$id, "_shortcut")on every translated source node AND renders the sibling shortcuttextInput(atnode$shortcut_id) for you — an "Optional dataset name" box beside the source widget (ADR 0025 item #7). Yourbuild_uirenders ONLY the data-payload widget atnode$id(orNULLfor a shortcut-only source); it must NOT render the shortcut input itself. Both inputs participate in the runtime substitution cycle: one atnode$id(the data payload) and one atnode$shortcut_id(a typed-in name that resolves adata.framefrom the caller-suppliedenvir). The shortcut value reachesresolve_data/resolve_exprthroughnode. Most sources do not need it — one bound input is the common case. The built-inppUploadsetsshortcut = TRUE: the file contents bind tonode$id, the user-typed name binds tonode$shortcut_id, and the substitution uses the name as the symbol inserted into the generated code. The framework also re-renders the source widget when the shortcut goes non-empty, clearing a stale display (ADR 0025 item #7). The reserved shared key"shortcut"is rejected at translate time (see ADR 0025 §1).- parse_positional_arg, parse_named_args
See
ptr_define_placeholder_value(). Source placeholders use the same arg-schema slots.- embellish_eval
Optional
function(...)body used when the placeholder is called as a plain-R function (outsideptr_app()).NULL(default) supplies a guard that aborts with a message naming the keyword and noting the call is only meaningful insideptr_app()— source placeholders typically have no out-of-app meaning (a file upload widget cannot produce data at the REPL). Override only if the source has a sensible plain-R interpretation.
Value
The runtime callable. Default for a source placeholder is a
guard that aborts when called outside an app context. Also called for
its registration side effect; use ptr_clear_placeholder() to remove
the entry.
spec= round-trip
The spec= mechanism (see ptr_app()) captures a sparse snapshot of
input values so the preserve-mode panel can publish a reproducible boot
state. For a source placeholder, ONE of two patterns must hold:
Shortcut pattern — set
shortcut = TRUE. The shortcut input's text value (typically the typed dataset name) carries the round-trip identity; the source's own value atnode$idis dropped from the spec, because it is typically a per-session Shiny artifact (afileInput()data.frame whosedatapathis a tempfile path that does not survive the session). The built-inppUploaduses this.Data-loading entry point (ADR 0024). When
shortcut = TRUE, the shortcut sibling is more than a name override for an uploaded frame — it is a typed-in shortcut for loading adata.framefrom the embedder's environment (envirpassed toptr_app()/ptr_server()). Any valid R name typed into the shortcut input (or seeded viaspec = list(<shortcut-id> = "df_name")) is looked up viaget(name, envir, inherits = TRUE)and bound as the resolved source frame, with OR withoutdefault=on the placeholder. The downstream pipeline, generated code panel, and consumer pickers all read the named frame fromstate$eval_envas if it had been uploaded. Failures surface on the inline error pane viaset_resolve_error:"Object 'x' not found in environment."/"Object 'x' is not a data frame."Lookup usesinherits = TRUE, so package exports become reachable — typing"plot"will resolve tographics::plotand then fail the "is not a data frame" check (loudly, not silently).Scalar pattern —
shortcut = FALSE. The widget's value atnode$idmust be a literal that round-trips throughdeparse()— a length-1 string / number / logical, or a simple atomic vector. TheselectInput-style example above qualifies (its value is a single string).
Source widgets whose primary value is a complex object (raw
fileInput() data.frame, environment, S4 instance, etc.) without
shortcut = TRUE cannot round-trip; opt into shortcut = TRUE and the
framework renders the sibling textInput(node$shortcut_id, ...) that
carries the binding name, mirroring ppUpload.
Examples
# A minimal in-memory dataset source (picks from pre-loaded data frames).
ptr_define_placeholder_source(
keyword = "dataset",
build_ui = function(node, label, ...) {
shiny::selectInput(node$id, label = label,
choices = c("mtcars", "iris"))
},
resolve_data = function(value, node, ...) {
if (length(value) != 1L || !nzchar(value)) return(NULL)
get(value, envir = as.environment("package:datasets"))
}
)
#> function (...)
#> rlang::abort(paste0("`", kw, "()` is only meaningful inside `ptr_app()`."))
#> <bytecode: 0x5558f1a9dc98>
#> <environment: 0x5558f27fd678>
ptr_clear_placeholder("dataset")
#> ✔ Cleared placeholder: "dataset".