0

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

Jason Aller
  • 3,541
  • 28
  • 38
  • 38
TT95F
  • 1
  • 2
  • I don't understand because your code is not complete. First there are missing quotes in yout HTML code: `onclick=get_id(this.id)` should be `onclick="get_id(this.id)"`. Now for your problem, does replacing `x %>% ......` with `ns(x) %>% .....` solve the problem? Otherwise please post a minimal reproducible example. – Stéphane Laurent Dec 07 '22 at 08:50
  • Thank you but it didn't work. I have just added most of the module code. – TT95F Dec 07 '22 at 16:59
  • This is not minimal. – Stéphane Laurent Dec 07 '22 at 17:00
  • I don't see how to make a minimal golem example so I cut out some chunks. Hope it is clearer now. – TT95F Dec 08 '22 at 08:21

0 Answers0