
Define a data-consumer placeholder (e.g. column picker)
Source:R/paintr-registry.R
ptr_define_placeholder_consumer.RdA consumer placeholder is a value placeholder that additionally
receives the columns of the upstream data frame — typically a column
picker. The built-in example is ppVar. See
vignette("ggpaintr-tutorial") § "Defining your own placeholders"
(consumer role).
Arguments
- keyword, ui_text_defaults
- build_ui
function(node, cols, data, label = NULL, selected = NULL, ...)returning a Shiny tag.colsis a character vector of upstream column names (use aschoices);character(0)before upstream resolves.datais the upstream data frame, orNULLwhile pending — read it only when you need column types / levels / ranges.Widget-seeding contract —
selected. Same precedence, omit-on-no-default, render-empty-when-empty, and never-read-node$defaultrules as for value placeholders — see the "Widget-seeding contract" block onptr_define_placeholder_value()for the authoritative description.Consumer-specific rule: filter through
intersect(). Always passselected = intersect(selected %||% character(0), cols)(or the equivalent column filter) to the underlying widget, not bareselected. Three cases collapse into one line:User-cleared widget (
selectedis empty) →intersect()returnscharacter(0), widget renders empty. Honors the render-empty-when-empty rule.Stale pick after upstream data swap (
selectednames a column no longer incols) →intersect()drops it cleanly. Without this,selectInputsilently falls back to its first choice (silent data mutation) andshinyWidgets::pickerInputenters a similarly broken state.Valid pick →
intersect()is a no-op, value flows through.
- resolve_expr
function(value, node, ...). For a column picker the typical body isrlang::sym(value)so the bare column name is spliced as an identifier rather than a string literal. Seeptr_define_placeholder_value()for allowed return types and theNULL-prunes-the-argument convention.- validate_session_input
Optional
function(value, ctx)called beforeresolve_expr. ReturnTRUE/NULLto accept; return a single character string to reject (surfaced inline as the error message, layer pruned). Useful when a stale selection no longer matches any upstream column after a data swap, or when only certain column types are admissible.ctxis a plain list with named fields:node(the placeholder AST node, carries$id,$keyword,$args),keyword(convenience alias fornode$keyword),upstream_cols(character vector of upstream column names — the same valuebuild_uireceived ascols), anddata(the upstream data frame — the same objectbuild_uireceived asdata).ctx$upstream_colsandctx$datamay both beNULLwhile upstream resolution is pending; the validator is not invoked when upstream has not yet resolved (the substitute walker skips the hook in that case). ggpaintr invokes this function asvalidate_input(value, ctx)— no other positional or named arguments are passed, andctxcarries exactly the four fields above. The signature does not require....- parse_positional_arg, parse_named_args
See
ptr_define_placeholder_value(). Consumer placeholders use the same arg-schema slots; theppVarbuilt-in passes a column-name validator here when used asppVar(mpg).- embellish_eval
Optional
function(x, ...)body used when the placeholder is called as a plain-R function.NULL(default) supplies the identity fromembellish_identity()(function(x, ...) x), matching the legacyppVar-styleaes()NSE shape (the symbol-passthrough convention). Override to give the consumer a non-identity plain-R meaning (e.g.embellish_symbol_to_string()).
Value
The runtime callable (identity by default; override with
embellish_eval = ...). Also called for its registration side effect; use
ptr_clear_placeholder() to remove it.
See also
vignette("ggpaintr-tutorial") § "Defining your own placeholders";
ptr_define_placeholder_value(), ptr_define_placeholder_source().
Examples
# A consumer that picks a numeric-only column.
# Note: `selected = NULL` formal (per the seeding contract) plus
# intersect() filter (per the consumer-specific rule). Empty input
# renders empty; a stale pick after a data swap drops cleanly.
ptr_define_placeholder_consumer(
keyword = "numvar",
build_ui = function(node, cols, data, label = NULL,
selected = NULL, ...) {
numeric_cols <- if (is.null(data)) character(0) else
names(data)[vapply(data, is.numeric, logical(1))]
retained <- intersect(selected %||% character(0), numeric_cols)
shiny::selectInput(node$id, label = label %||% "Numeric column",
choices = numeric_cols, selected = retained)
},
resolve_expr = function(value, node, ...) {
if (length(value) != 1L || !nzchar(value)) return(NULL)
rlang::sym(value)
},
validate_session_input = function(value, ctx) {
if (length(value) == 1L && value %in% ctx$upstream_cols) TRUE
else "Pick a column that exists in the upstream data."
}
)
#> function (x, ...)
#> x
#> <bytecode: 0x5558f1b3ec88>
#> <environment: 0x5558ee210c48>
ptr_clear_placeholder("numvar")
#> ✔ Cleared placeholder: "numvar".