Interfaccia dinamica con renderUI e insertUI
Generi elementi dell'interfaccia al volo in base all'input dell'utente e allo stato del server
Interfaccia dinamica con renderUI e insertUI è una lezione R Academy gratuita su CoddyKit. Questa è la lezione 3 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento R Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso R Academy include 4 lezioni in totale.
UI dinamica — Perché e quando
A volte la UI necessaria non può essere determinata completamente all'avvio dell'app: dipende dalle scelte dell'utente, dai dati caricati o dalle condizioni di runtime. Shiny offre due meccanismi: renderUI() per sostituire interamente il contenuto di un segnaposto e insertUI()/removeUI() per aggiungere o rimuovere elementi senza sostituire tutto.
library(shiny)
# Static UI: columns always shown
# ui <- fluidPage(selectInput('x', ...), selectInput('y', ...))
# Dynamic UI: columns depend on which dataset was loaded
# ui <- fluidPage(fileInput('upload', ...), uiOutput('var_selectors'))renderUI() e uiOutput()
renderUI({...}) nel server costruisce e restituisce reattivamente un elemento UI. uiOutput('id') nella UI crea un segnaposto che visualizza ciò che produce renderUI. L'intero contenuto del segnaposto viene sostituito ogni volta che il reattivo viene rieseguito.
ui <- fluidPage(
selectInput('dataset', 'Dataset:', choices = c('iris', 'mtcars')),
uiOutput('column_selector') # placeholder
)
server <- function(input, output, session) {
output$column_selector <- renderUI({
df <- get(input$dataset) # reactive dependency on dataset
selectInput('col', 'Choose Column:',
choices = names(df))
})
}
shinyApp(ui, server)renderUI() con più controlli
Restituisca una tagList() da renderUI() per visualizzare più elementi UI contemporaneamente. Questo è il modello standard quando il numero di controlli dipende dai dati, ad esempio per generare un filtro per ogni colonna di un dataset.
server <- function(input, output, session) {
output$filters <- renderUI({
df <- get(input$dataset)
nums <- names(df)[sapply(df, is.numeric)]
# One slider per numeric column
sliders <- lapply(nums, function(col) {
rng <- range(df[[col]], na.rm = TRUE)
sliderInput(
inputId = paste0('filter_', col),
label = col,
min = rng[1], max = rng[2],
value = rng
)
})
tagList(sliders) # render all sliders
})
}insertUI() — Aggiunta dinamica di elementi
insertUI(selector, where, ui) inserisce un elemento UI nel DOM senza ricostruire l'intera pagina. Utilizzi i selettori CSS per identificare il punto di inserimento. where può essere 'afterEnd', 'beforeEnd', 'afterBegin' oppure 'beforeBegin'.
server <- function(input, output, session) {
item_count <- reactiveVal(0)
observeEvent(input$add_item, {
item_count(item_count() + 1)
id <- paste0('item_', item_count())
insertUI(
selector = '#item_container', # CSS selector
where = 'beforeEnd',
ui = div(
id = id,
style = 'padding: 5px; border: 1px solid #ccc; margin: 3px;',
textInput(id, paste('Item', item_count()), value = '')
)
)
})
}removeUI() — Eliminazione di elementi
removeUI(selector) rimuove il primo elemento DOM che corrisponde al selettore CSS. Utilizzi multiple = TRUE per rimuovere tutti gli elementi corrispondenti. È il complemento di insertUI() per le UI basate su elenchi, in cui gli utenti possono aggiungere e rimuovere elementi.
server <- function(input, output, session) {
observeEvent(input$remove_last, {
# Remove the last item div
n <- isolate(item_count())
if (n > 0) {
removeUI(selector = paste0('#item_', n))
item_count(n - 1)
}
})
observeEvent(input$clear_all, {
# Remove all items matching a class
removeUI(selector = '.dynamic-item', multiple = TRUE)
item_count(0)
})
}conditionalPanel() — Visibilità lato client
conditionalPanel(condition, ...) mostra o nasconde gli elementi UI in base a una condizione JavaScript valutata nel browser. A differenza di renderUI(), gli elementi sono sempre presenti nel DOM: vengono semplicemente visualizzati o nascosti. È più rapido per una semplice logica di visualizzazione e occultamento, perché non richiede un viaggio di andata e ritorno al server.
ui <- fluidPage(
selectInput('plot_type', 'Plot Type:',
choices = c('scatter', 'histogram', 'boxplot')),
# Only shown when scatter is selected
conditionalPanel(
condition = "input.plot_type == 'scatter'",
selectInput('x_var', 'X Variable:', choices = names(mtcars)),
selectInput('y_var', 'Y Variable:', choices = names(mtcars))
),
# Only shown when histogram is selected
conditionalPanel(
condition = "input.plot_type == 'histogram'",
sliderInput('bins', 'Number of bins:', 5, 50, 20)
),
plotOutput('main_plot')
)updateSelectInput() — Modifica degli input esistenti
Anziché sostituire un intero controllo di input, utilizzi updateSelectInput(session, id, choices, selected) per aggiornare solo le scelte o il valore selezionato di un selectInput esistente. Funzioni di aggiornamento analoghe esistono per tutti i tipi di input: updateSliderInput(), updateTextInput() e così via.
server <- function(input, output, session) {
# When dataset changes, update the column selector
observeEvent(input$dataset, {
df <- get(input$dataset)
updateSelectInput(
session = session,
inputId = 'column',
choices = names(df),
selected = names(df)[1]
)
})
# Reset slider when reset button pressed
observeEvent(input$reset_btn, {
updateSliderInput(session, 'n_items',
value = 20, min = 1, max = 100)
})
}updateSliderInput() e updateNumericInput()
Le funzioni di aggiornamento inviano un messaggio al browser per modificare il valore corrente, il minimo, il massimo o l'etichetta di un input esistente. È più efficiente che distruggere e ricreare il controllo con renderUI() e ne preserva la posizione nel layout della pagina.
server <- function(input, output, session) {
# When data loads, set slider max to actual data length
observeEvent(input$load_data, {
data <- readRDS(input$upload$datapath)
updateSliderInput(session, 'row_slider',
min = 1,
max = nrow(data),
value = c(1, min(50, nrow(data)))
)
updateNumericInput(session, 'page_size',
max = nrow(data),
value = min(10, nrow(data))
)
})
}Accesso agli input di renderUI con req()
Gli input creati dinamicamente con renderUI() sono NULL finché non vengono visualizzati. Utilizzi req(input$dynamic_input) in qualsiasi codice server che dipenda da input creati dinamicamente, per prevenire errori durante l'inizializzazione.
server <- function(input, output, session) {
# dynamic input: 'col' is created by renderUI
output$column_selector <- renderUI({
selectInput('col', 'Column:', choices = names(get(input$dataset)))
})
output$summary_stats <- renderPrint({
req(input$col) # wait until 'col' exists
req(input$dataset) # and dataset is chosen
df <- get(input$dataset)
summary(df[[input$col]])
})
}Schede dinamiche con appendTab()
appendTab(inputId, tab, select) aggiunge una nuova scheda a un tabsetPanel() durante l'esecuzione. removeTab(inputId, target) ne rimuove una. Questo modello consente flussi di lavoro in cui gli utenti aprono, chiudono e alternano viste di analisi generate dinamicamente.
ui <- fluidPage(
actionButton('add_tab', 'Open New Analysis Tab'),
tabsetPanel(id = 'analysis_tabs', type = 'tabs')
)
server <- function(input, output, session) {
tab_count <- reactiveVal(0)
observeEvent(input$add_tab, {
tab_count(tab_count() + 1)
n <- tab_count()
appendTab(
inputId = 'analysis_tabs',
select = TRUE,
tab = tabPanel(
title = paste('Analysis', n),
value = paste0('tab_', n),
plotOutput(paste0('plot_', n)),
actionButton(paste0('close_', n), 'Close')
)
)
})
}renderUI e insertUI — Quando utilizzare l'uno o l'altro
Scelga lo strumento giusto in base al caso d'uso:
- renderUI(): sostituisce reattivamente l'intero contenuto di un segnaposto. È ideale quando l'intero blocco cambia contemporaneamente.
- insertUI(): aggiunge nuovi elementi al contenuto esistente. È ideale per elenchi che crescono e che non si desidera visualizzare nuovamente per intero.
- updateXxxInput(): modifica un input esistente direttamente sul posto. È ideale per cambiare scelte o valori senza eseguire nuovamente il rendering.
- conditionalPanel(): mostra o nasconde senza un viaggio di andata e ritorno al server. È ideale per una semplice logica di visibilità.
# Decision guide:
# - 'Show filter only when advanced mode' -> conditionalPanel
# - 'Populate column choices from loaded CSV' -> updateSelectInput
# - 'Show different controls per selected tab' -> renderUI
# - 'Add a row editor for each row user adds' -> insertUI
# - 'Remove a row editor' -> removeUI
# Combining strategies:
server <- function(input, output, session) {
# Use renderUI for column selectors (replaces whole block)
output$col_selectors <- renderUI({ ... })
# Use insertUI for dynamically added rows
observeEvent(input$add_row, { insertUI(...) })
# Use conditionalPanel for show/hide (in UI, no server code)
}Verifica rapida
Qual è la differenza fondamentale tra renderUI() e insertUI() per creare una UI dinamica in Shiny?
Riepilogo della UI dinamica
Punti chiave della UI dinamica con renderUI e insertUI:
renderUI({}) + uiOutput('id'): sostituisce reattivamente l'intero contenuto di un segnaposto.- Restituisca
tagList()darenderUI()per visualizzare più elementi contemporaneamente. insertUI(selector, where, ui): inserisce elementi in qualsiasi posizione del DOM.removeUI(selector): rimuove elementi tramite selettore CSS.conditionalPanel(condition, ...): mostra o nasconde gli elementi lato client senza ricorrere al server.updateSelectInput(),updateSliderInput(): modificano gli input esistenti direttamente sul posto.- Utilizzi sempre
req(input$dynamic_id)per gestire il valore NULL prima del rendering degli input dinamici.
# Typical pattern: dynamic column selector
ui <- fluidPage(
fileInput('upload', 'Upload CSV'),
uiOutput('col_ui'), # placeholder
plotOutput('col_plot')
)
server <- function(input, output, session) {
df <- reactive({
req(input$upload)
read.csv(input$upload$datapath)
})
output$col_ui <- renderUI({
req(df())
selectInput('col', 'Column:', choices = names(df()))
})
output$col_plot <- renderPlot({
req(input$col)
hist(df()[[input$col]])
})
}Domande Frequenti
La lezione «Interfaccia dinamica con renderUI e insertUI» è gratuita?
Sì — il testo completo di «Interfaccia dinamica con renderUI e insertUI» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso R Academy, passa a CoddyKit PRO. Il corso R Academy include 4 lezioni in totale.
Cosa imparerò in «Interfaccia dinamica con renderUI e insertUI»?
Generi elementi dell'interfaccia al volo in base all'input dell'utente e allo stato del server Eserciti R Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare R Academy?
Non è richiesta alcuna esperienza precedente. R Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 3 di 4.
Quanto tempo richiede la lezione «Interfaccia dinamica con renderUI e insertUI»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione R Academy?
Sì. Ogni lezione R Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Approfondimento della programmazione reattiva
- Moduli Shiny per riutilizzare il codice
- Interfaccia dinamica con renderUI e insertUI
- Distribuzione delle app Shiny