Skip to content

Instantly share code, notes, and snippets.

@beader
Last active August 6, 2020 02:21
Show Gist options
  • Save beader/bbf2221ab6f84a819c0f to your computer and use it in GitHub Desktop.
Save beader/bbf2221ab6f84a819c0f to your computer and use it in GitHub Desktop.
ShinyApp - Dynamically Add/Remove UI Elements
Title: Dynamically Remove UI Elements
Author: beader.chen@gmail.com
DisplayMode: Showcase
Type: Shiny
library(shiny)
removeMeButton <- function(id, label = paste0("Remove Me, I am ", id)) {
actionButton(paste0("rmBtn", id), label = label)
}
shinyServer(function(input, output) {
container <- reactiveValues(uiComponents = list())
output$container <- renderUI({
container$uiComponents
})
observe({
if(is.null(input$addBtn) || input$addBtn == 0) return()
isolate({
uiComponentCount <- length(container$uiComponents)
container$uiComponents <- append(
container$uiComponents,
list(
list(
"removeBtn" = removeMeButton(id = as.integer(runif(1,1e5,1e6-1))),
br(),br()
)
)
)
})
})
observe({
if(length(container$uiComponents) == 0) return()
rmBtns <- lapply(container$uiComponents, `[[`, "removeBtn")
rmBtnIds <- sapply(container$uiComponents, function(uiCom) {
uiCom$removeBtn$attribs$id
})
rmBtnVals <- sapply(rmBtnIds, function(btnId) input[[btnId]])
if(any(sapply(rmBtnVals, is.null))) return()
if(all(rmBtnVals == 0)) return()
isolate({
container$uiComponents[[which(rmBtnVals > 0)]] <- NULL
})
})
})
library(shiny)
shinyUI(fluidPage(
titlePanel("Dynamically Add/Remove UI Elements"),
hr(),
actionButton("addBtn", "Add"),
br(),br(),
uiOutput("container")
))
@jameswcraig
Copy link

Hi @beader @grayskripko I've tested your example with a selectInput() and the selection made to the previously added selectInput() is reset each time a new input is added. Have you found a way to implement the above (adding new inputs) while retaining the selected value in the existing selectInput(). Note: I am unable to use insertUI() and removeUI() for my particular use case.

See reprex below:

library(shiny)

# function to render UI element
removeMeButton <- function(id, label = paste0("Remove Me, I am ", id)) {
  actionButton(paste0("rmBtn", id), label = label)
}

dropdownUI <- function(id) {
  selectInput(paste0("dropdown", id), label = NULL, choices = c("A", "B", "C"))
}

server <- function(input, output, session){

  container <- reactiveValues(uiComponents = list())
  
  output$container <- renderUI({
    container$uiComponents
  })
  
  observe({
    if(is.null(input$addBtn) || input$addBtn == 0) return()
    
    isolate({
      uiComponentCount <- length(container$uiComponents)
      container$uiComponents <- append(
        container$uiComponents, 
        list(
          list(
            "removeBtn" = removeMeButton(id = as.integer(runif(1,1e5,1e6-1))),
            "dropdownSelection" = dropdownUI(id = as.integer(runif(1,1e5,1e6-1))),
            br(),br()
          )
        )
      )
    })
  })
  
  observe({
    if(length(container$uiComponents) == 0) return()
    rmBtns <- lapply(container$uiComponents, `[[`, "removeBtn")
    rmBtnIds <- sapply(container$uiComponents, function(uiCom) {
      uiCom$removeBtn$attribs$id
    })
    rmBtnVals <- sapply(rmBtnIds, function(btnId) input[[btnId]])
    if(any(sapply(rmBtnVals, is.null))) return()
    if(all(rmBtnVals == 0)) return()
    isolate({
      container$uiComponents[[which(rmBtnVals > 0)]] <- NULL
    })
  })
  
}


ui <- fluidPage(
  titlePanel("Dynamically Add/Remove UI Elements"),
  hr(),
  actionButton("addBtn", "Add"),
  br(),br(),
  uiOutput("container")
)

shinyApp(ui, server)

@beader
Copy link
Author

beader commented Aug 6, 2020

Hi @jameswcraig
I think I have totally forgot what I have written almost 6 years ago.
BTW, I think Python Voila project can do a better job for writing "tiny" data analysis web applications.
I am sorry I can't help.

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