Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Conversation

gadenbuie
Copy link
Member

@gadenbuie gadenbuie commented Sep 23, 2025

For #2374

This is a bit of proof-of-concept, but isn't far from something we could ship. The idea is to add a $remove() method to ReactiveValues and a session$removeInputs() that uses this method to remove a key from a reactive values list. Some notes:

  1. Removing an input only removes it from the list of inputs, without invalidating its value. This means that downstream observers that use this value directly aren't updated unless by another method. This preserves the current behavior, but if a future update is performed (because another reactive value is invalidated), reading the removed input has the same behavior as reading an un-initialized input.

  2. On the other hand, we do invalidate names(input) and reactiveValuesToList(input), since these have effectively changed due to the removal of the input.

  3. session$removeInputs() removes the input from the map on the server side. It does not change behavior on the client. We may need to revisit this and potentially remove any bindings to the input ID. I think this might be a good idea to ensure that if you add a new input UI with the same ID as a previous, but server-side removed input, it will be treated as a brand-new input. An alternative would be to make sure that UI added via insertUI() and renderUI() always report input values when bound (as opposed to only reporting changed values if the initial value is different from the last value before it was removed).

Here's a small app that shows all of the above behavior:

library(shiny)

ui <- fluidPage(
  actionButton("toggle", "Toggle Input UI"),
  div(
    id = "removable-input",
    textInput("txt", "This is no longer useful", "beep"),
  ),
  textInput("txt2", "Some other text", "boop"),
  p(
    "As of",
    textOutput("ui_time", inline = TRUE),
    "the first inputs says",
    uiOutput("ui_txt", inline = TRUE),
    "and the second input says",
    uiOutput("ui_txt2", inline = TRUE)
  ),
  actionButton("update", "Update text output"),
  h3("Names"),
  verbatimTextOutput("names"),
  h3("Values"),
  verbatimTextOutput("values")
)

# Server logic
server <- function(input, output, session) {
  observeEvent(input$toggle, {
    if (input$toggle %% 2 == 0) {
      insertUI(
        selector = "#removable-input",
        ui = textInput("txt", "This is no longer useful", "beep")
      )
    } else {
      removeUI(
        selector = "#removable-input .form-group"
      )
      session$removeInputs("txt")
    }
  })

  output$ui_time <- renderText({
    input$update
    strftime(Sys.time(), "%F %T,")
  })

  output$ui_txt <- renderText({
    input$update
    HTML(sprintf("<code>%s</code>", input$txt))
  })

  output$ui_txt2 <- renderText({
    input$update
    HTML(sprintf("<code>%s</code>.", input$txt2))
  })

  output$names <- renderPrint({
    names(input)
  })

  output$values <- renderPrint({
    reactiveValuesToList(input)
  })
}

shinyApp(ui, server)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

Morty Proxy This is a proxified and sanitized view of the page, visit original site.