Search code examples
rshinyjquery-ui-sortablesortablejsshinyalert

Cannot add sortable::rank_list() inside of a shinyalert or modal


I am trying to add a rank_list from the sortable library in a Shiny application. This seems to work fine if the input is in the fluid page part of the UI. When I add it to a shinyalert() or a modal, the input shows up in popup but the choices aren't sortable or even selectable.

In the repex below I have added a selectInput to see if it renders that correctly and interactively - it does.

library(shiny)
library(sortable)
library(shinyalert)

labels <- list(
  "one",
  "two",
  "three",
  htmltools::tags$div(htmltools::em("Complex"), " html tag without a name"),
  "five" = htmltools::tags$div(htmltools::em("Complex"), " html tag with name: 'five'")
)
rank_list_multi <- rank_list(
  text = "You can select multiple items, then drag as a group",
  labels = labels,
  input_id = "rank_list_multi",
  options = sortable_options(multiDrag = TRUE)
)



ui <- fluidPage(rank_list_multi,
                actionButton("showAlert", "Show in popup"))


server <- function(input, output, session) {
  observeEvent(input$showAlert, {
    print("Show popup")
    
    shinyalert(
      title = "Reorder this object",
      html = TRUE,
      closeOnClickOutside = TRUE,
      showConfirmButton = TRUE,
      text = tagList(
        rank_list_multi,
        br(),
        selectInput("alertTextInput", "Select Letter", choices = c("a", "b", "C"))
      )
      
    )
    
  })
}

shinyApp(ui, server)

Sortable working on the main page:

enter image description here

Sortable NOT working in the pop up modal:

enter image description here

I saw this link asking the same but not for the shiny package sortable Any help is appreciated


Solution

  • The Issue

    The problem here is that you're trying to use the same UI object in two locations: the rank_list_multi appears in both the main fluidPage and in the shinyalert.

    You should create two separate sortable objects each with a unique input_id. You can do this using a generator function like I've constructed below.

    Example Solution

    library(shiny)
    library(sortable)
    library(shinyalert)
    
    
    #' Construct a sortable rank list object.
    #' 
    #' @param input_id The shiny ID used to construct the rank list.
    construct_rank_list <- function(input_id) {
      sortable::rank_list(
        text = "Drag to Reorder",
        labels = c(1:5),
        input_id = input_id,
        options = sortable_options(multiDrag = TRUE)
      )
    }
    
    
    ui <- fluidPage(construct_rank_list("rank_list_multi"),
                    actionButton("showAlert", "Show in popup"))
    
    
    server <- function(input, output, session) {
      observeEvent(input$showAlert, {
        shinyalert::shinyalert(
          title = "Reorder this object",
          html = TRUE,
          closeOnClickOutside = TRUE,
          showConfirmButton = TRUE,
          text = tagList(
            construct_rank_list("rank_list_modal")
          )
        )
      })
    }
    
    shinyApp(ui, server)