I have adapted some CRUD code which works perfectly in a classical shiny app. I decided to include it in a golem module. But in golem the edit and delete buttons don't launch the modal window.
I checked if I missed some ns(), but I don't think so. I have also tried to load in a different way the get_id() function (see below) but it changed nothing.
The only curious clue I found was in the browser dev environment which indicated "Couldn't find table with id CRUD_1-dt_table"
I am new to Stack Overflow. Thank your for your help.
Please find below the code in script.js which seems to be loaded normally
function get_id(clicked_id) {
Shiny.setInputValue("current_id", clicked_id, {priority: "event"});
}
The code is simple for the UI part of the module
mod_CRUD_ui <- function(id){
ns <- NS(id)
tagList(
# Button to add a project -> it works
div(
class = "container",
div(
style = "margin-top: 50px;", shiny::actionButton(
inputId = ns("add_project"), label = "Ajouter un projet",
icon = shiny::icon("plus"), class = "btn-success"
)
)
),
# To display the DT table
div(
class = "container",
style = "margin-top: 50px;",
DT::DTOutput(outputId = ns("dt_table"), width = "100%")
),
shiny::includeScript(system.file("app/www", "script.js", package = "REXDI"))
# shiny::includeScript("app/www/script.js")
# tags$script(src= "script.js")
)
}
The data is first contained in global$CRUD_init (reactiveValues) which is initialized when the app is launched in another module
#' CRUD Server Functions
mod_CRUD_server <- function(id, global){
moduleServer( id, function(input, output, session){
ns <- session$ns
observeEvent(global$CRUD_init , {
global$CRUD_init_co <- global$CRUD_init
# the get_id() function from the script.js file is used in the next part of # the code. Normally it works
global$create_btns <- function(x) {
x %>%
purrr::map_chr(~
paste0(
'<div class = "btn-group">',
'<button class="btn btn-default action-button btn-info action_button" id="edit_',
.x, '" type="button" onclick=get_id(this.id)>
<i class="fas fa-edit"></i>
</button>
<button class="btn btn-default action-button btn-danger action_button" id="delete_',
.x, '" type="button" onclick=get_id(this.id)>
<i class="fa fa-trash-alt"></i>
</button>
</div>'
))
}
# Buttons in df global$CRUD
x <- global$create_btns(global$CRUD_init_co$id)
global$CRUD_init_co <- global$CRUD_init_co %>%
dplyr::bind_cols(tibble("Buttons" = x))
## reactiveValues global$CRUD ----
global$CRUD <- shiny::reactiveValues(
df = global$CRUD_init_co %>%
dplyr::select(-id),
dt_row = NULL,
add_or_edit = NULL,
edit_button = NULL,
keep_track_id = max(global$CRUD_init_co$id) + 1
)
})
It is followed by the function modal_dialog (because it's long I kept only few arguments and inputs
modal_dialog <- function(Projet,
Centre,
...and so forth...,
edit) {
if(edit) {
x <- "Soumettre modifications"
} else {
x <- "Ajouter un projet"
}
shiny::modalDialog(
title = "Editer un projet",
div(
class = "text-center",
div(
style = "display: inline-block;",
shiny::textInput(inputId = ns("Projet"),
label = "Projet",
value = Projet,
placeholder = "",
width = "200px")
),
div(
style = "display: inline-block;",
shiny::textInput(inputId = ns("Centre"),
label = "Centre",
value = Centre,
placeholder = "Entrer un Centre",
width = "200px")
),
...and so forth...
),
size = 'm',
easyClose = TRUE,
footer = div(
class = "pull-right container",
shiny::actionButton(inputId = ns("final_edit"),
label = x,
icon = shiny::icon("edit"),
class = "btn-info"),
shiny::actionButton(inputId = ns("dismiss_modal"),
label = "Fermer",
class = "btn-danger")
)
) %>% shiny::showModal()
}
I also tried to add ns("dt_table") to DT::dataTableProxy("dt_table") but it did not work and I am not really sure to understand the dataTableProxy in a module
## output DT ----
output$dt_table <- DT::renderDT(
{
shiny::isolate(global$CRUD$df)
},
escape = F,
rownames = FALSE,
options = list(processing = FALSE)
)
## Proxy DT ----
proxy <- DT::dataTableProxy("dt_table")
shiny::observe({
DT::replaceData(proxy, global$CRUD$df, resetPaging = FALSE, rownames = FALSE)
})
The code for deleting is clear
## delete row ----
shiny::observeEvent(input$current_id, {
shiny::req(!is.null(input$current_id) &
stringr::str_detect(input$current_id,
pattern = "delete"
))
global$CRUD$dt_row <- which(stringr::str_detect(global$CRUD$df$Buttons,
pattern = paste0("\\b", input$current_id, "\\b")
))
The purpose of the next chunk of code is only for keeping memory of what has been deleted, so I did not include it in this post
then deleting
sql_id <- global$CRUD$df[global$CRUD$dt_row, ][["Buttons"]] %>%
stringr::str_extract_all(pattern = "delete_[0-9]+") %>%
unlist() %>%
readr::parse_number()
query <- stringr::str_glue("DELETE FROM TDP WHERE id = {sql_id}")
DBI::dbSendQuery(
con,
query
)
...
})
The edit part like the deleting part is not launched when clicking on the buttons. All the code works in a classic shiny app, and I don't see any missing ns(), so it is a mystery for me
# when edit button is clicked, modal dialog shows current editable row filled out ----
shiny::observeEvent(input$current_id, {
shiny::req(!is.null(input$current_id) &
stringr::str_detect(input$current_id,
pattern = "edit"
))
global$CRUD$dt_row <- which(stringr::str_detect(global$CRUD$df$Buttons,
pattern = paste0("\\b", input$current_id, "\\b")
))
df <- global$CRUD$df[global$CRUD$dt_row, ]
modal_dialog(
### A modifier -----
Projet = df$Projet,
Centre = df$Centre,
...and so forth or else the code is too long...
edit = TRUE
)
global$CRUD$add_or_edit <- NULL
})
# when final edit button is clicked, table will be changed ----
shiny::observeEvent(input$final_edit, {
shiny::req(!is.null(input$current_id) &
stringr::str_detect(input$current_id, pattern = "edit") &
is.null(global$CRUD$add_or_edit))
global$CRUD$edited_row <- dplyr::tibble(
Projet = input$Projet,
Centre = input$Centre,
....and so forth...or else it is too long
Buttons = global$CRUD$df$Buttons[global$CRUD$dt_row]
)
sql_row <- global$CRUD$edited_row %>%
dplyr::select(-Buttons)
id <- global$CRUD$df[global$CRUD$dt_row, ][["Buttons"]] %>%
stringr::str_extract_all(pattern = "delete_[0-9]+") %>%
unlist() %>%
readr::parse_number()
# browser()
query <- paste0(
"UPDATE TDP SET ",
paste0(names(sql_row), "=", "'", unlist(c(sql_row)), "'", collapse = ", "),
stringr::str_glue("WHERE id = {id}")
)
DBI::dbSendQuery(
global$con,
query
)
global$CRUD$df[global$CRUD$dt_row, ] <- global$CRUD$edited_row
})
The next part is for adding a project which works so it is not added below and then code to remove modals