Skip to content

Instantly share code, notes, and snippets.

@geebioso
Last active June 20, 2019 19:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save geebioso/8d1c3a165a3968beddd95bf736db1b01 to your computer and use it in GitHub Desktop.
Save geebioso/8d1c3a165a3968beddd95bf736db1b01 to your computer and use it in GitHub Desktop.
This code creates deletable dynamic accordions that load a modal when they are created. The modal is triggering too many times after an accordion is deleted and then reloaded.
makeReactiveTrigger <- function() {
rv <- shiny::reactiveValues(a = 0)
list(
depend = function() {
rv$a
},
trigger = function() {
rv$a <- shiny::isolate(rv$a + 1)
}
)
}
# Test Module ---------------------------------------------------------------
library(shiny)
library(glue)
load("~/git_repos/lrw-ms-shinyapps/shinyutility/testimage.rdata")
ui <- fluidPage(
tagList(
tags$div(id = "RowPlaceholder", class = 'box-group'),
actionButton('add', label = "Add accordions"),
actionButton('delete', label = "Delete accordions")
)
)
server <- function(input, output, session) {
auto_populate_btn = reactive(input$add)
do_delete_all = reactive(input$delete)
#!!! you can change the number of batteries if it helps debug
auto_stack_instructions = reactiveVal(c("Battery1", "Battery2"))
current_accordions <- reactiveVal()
auto_pop_modal <- modalDialog(
div(style = "text-align: center; font-size: 28px;",
h2("Auto Populating"), #, style = "text-align: center;"),
icon("spinner", class = "fa-spin")),
footer = NULL, size = 'm')
delete_trigger <- makeReactiveTrigger()
delete_all = reactive({
do_delete_all() # actionButton
delete_trigger$depend() # trigger off the auto_populate_btn actionButton
})
num <- reactiveVal(0)
insert_accordion <- function(
battery_name,
auto_populate_btn = auto_populate_btn,
delete = delete_all,
auto_pop_modal){
current_accordions(c(current_accordions(), battery_name))
accordion_item_div_id <- glue::glue("accordion_item_div_{battery_name}")
accordion_item_id <- glue::glue("accordion_item_{battery_name}")
delete_btn_id <- glue::glue("delete_{battery_name}")
accordion_item <-
tags$div(id = accordion_item_div_id,
shinydashboardPlus::accordionItem(
id = accordion_item_id,
title = battery_name,
color = "secondary",
collapsed = FALSE,
shiny::actionButton(
delete_btn_id, label = NULL,
icon = shiny::icon("trash-alt"), width = '40px')
)
)
insertUI(
selector = glue::glue("#{'RowPlaceholder'}"),
where = "beforeEnd",
ui = accordion_item,
immediate = TRUE
)
delete_module_trigger <- makeReactiveTrigger()
# !!! Dean - this observeEvent will eventually be inside a sub-module that is called
# for each accordion. The idea is to pass the modal through to a sub-module
# and have it display when we are peforming some computations there. I pulled
# it out of the sub-module because we still see the bug here
observeEvent(auto_populate_btn(), {
showModal(auto_pop_modal)
Sys.sleep(2)
removeModal()
})
delete_accordion <- function(delete_btn_id){
delete_accordion_num <- strsplit(delete_btn_id, "delete_")[[1]][2]
accordion_item_div_id <- glue::glue("accordion_item_div_{delete_accordion_num}")
delete_btn_id <- glue::glue("delete_{delete_accordion_num}")
removeUI(selector = glue::glue("#{accordion_item_div_id}"), immediate = TRUE)
shinyjs::runjs(glue::glue("Shiny.onInputChange(‘{accordion_item_div_id}’, null)"))
shinyjs::runjs(glue::glue("Shiny.onInputChange(‘{delete_btn_id}’, null)"))
current_accordions(
current_accordions()[-match(delete_accordion_num, current_accordions())]
)
}
observeEvent(auto_populate_btn(), delete_trigger$trigger(),
ignoreInit = TRUE, priority = 2)
observeEvent(input[[delete_btn_id]],{
delete_accordion(delete_btn_id)
delete_module_trigger$trigger()
}, once = TRUE, ignoreInit = TRUE)
observeEvent(delete(),{
delete_accordion(delete_btn_id)
}, once = TRUE, ignoreInit = TRUE, priority = 2)
}
#------------------------------------------------------- end insert_accordion
observeEvent(auto_populate_btn(), {
lapply(auto_stack_instructions(), function (battery){
if (!battery %in% current_accordions()){
insert_accordion(
battery_name = battery,
auto_populate_btn = auto_populate_btn,
delete = delete_all,
auto_pop_modal
)
}
})
}, priority = 1)
}
shinyApp(ui, server)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment