-
-
Save daattali/75dc075f173ba4b11305ed53e78a83a2 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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
makeReactiveTrigger <- function() { | |
rv <- shiny::reactiveValues(a = 0) | |
list( | |
depend = function() { | |
rv$a | |
}, | |
trigger = function() { | |
rv$a <- shiny::isolate(rv$a + 1) | |
} | |
) | |
} | |
library(shiny) | |
library(glue) | |
ui <- fluidPage( | |
tags$div(id = "RowPlaceholder"), | |
actionButton('add', label = "Add 2 accordions"), | |
actionButton('delete', label = "Delete accordions") | |
) | |
server <- function(input, output, session) { | |
#!!! you can change the number of batteries if it helps debug | |
rows_to_create <- c("name1", "name2") | |
current_accordions <- reactiveVal() | |
auto_pop_modal <- modalDialog(h2("Auto Populating"), footer = NULL) | |
delete_trigger <- makeReactiveTrigger() | |
delete_all <- reactive({ | |
input$delete | |
delete_trigger$depend() # trigger off the auto_populate_btn actionButton | |
}) | |
num <- reactiveVal(0) | |
insert_accordion <- function( | |
row_name, | |
delete = delete_all, | |
auto_pop_modal) { | |
if (row_name %in% current_accordions()) return() | |
current_accordions(c(current_accordions(), row_name)) | |
accordion_item_div_id <- glue::glue("accordion_item_div_{row_name}") | |
accordion_item_id <- glue::glue("accordion_item_{row_name}") | |
delete_btn_id <- glue::glue("delete_{row_name}") | |
accordion_item <- div( | |
id = accordion_item_div_id, | |
accordion_item_div_id, | |
actionButton(delete_btn_id, NULL, icon = icon("trash")) | |
) | |
insertUI( | |
selector = glue::glue("#{'RowPlaceholder'}"), | |
where = "beforeEnd", | |
ui = accordion_item, | |
immediate = TRUE | |
) | |
# !!! 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(input$add, { | |
showModal(auto_pop_modal) | |
Sys.sleep(0.3) | |
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(input$add, { | |
delete_trigger$trigger() | |
}, ignoreInit = TRUE, priority = 2) | |
observeEvent(input[[delete_btn_id]],{ | |
delete_accordion(delete_btn_id) | |
}, once = TRUE, ignoreInit = TRUE) | |
observeEvent(delete(),{ | |
delete_accordion(delete_btn_id) | |
}, once = TRUE, ignoreInit = TRUE, priority = 2) | |
} | |
observeEvent(input$add, { | |
lapply(rows_to_create, function (name) { | |
insert_accordion( | |
row_name = name, | |
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