javascriptjquerycssshinyjquery-ui-sortable

adding custom class by row in RShiny using jQuery


This question is just an extention of this question

The following code consists of two containers or divs or bucket_lists from the sortable R package and each bucket_list consists of two add_rank_list functions.

The first container elements are completly unmovable where the disabled arguments in each add_rank_list are set to TRUE, while the second container allows the user to drag and drop the items except the first item, since the disabled argument in the first add_rank_list function is set to TRUE but in the second function is set to FALSE.

I would like to apply a red background color to the element in the second container if its value is "Camp". Additionally, I would like to apply the same background color to the element in the first container that shares the same row with the "Camp" element.

So briefly I do not have a problem with adding the class to the "Camp" element in the second container since my code can do this. However, my main point is to add the class to the element in the first container which has the same row as the "Camp" element in the second container and take into consideration that the user can drag and drop "Camp" element in the second container.

Despite attempting different methods, I have been unable to achieve this outcome. Any assistance would be greatly appreciated.

library(shiny)
library(sortable)

ui <- fluidPage(
  actionButton(inputId = "id1", "run"),
  uiOutput("id2")
)

server <- function(input, output, session) {
  observeEvent(input$id1, {
    output$id2 <- renderUI({
      
      tagList(
        tags$style(
          HTML(paste0("
              .custom-sortable .rank-list-item-Camp {
              background-color: red 
              }
                      "))
        ),
        tags$script(
          HTML("
                $(document).ready(function() {
                $('.custom-sortable .rank-list-item').each(function(index) {
                if ($(this).text() === 'Camp') {
                targetIndex = index;
                }
                });
                $('.custom-sortable .rank-list-item').eq(targetIndex).addClass('rank-list-item-Camp');
                });
                     ")
        ),
        div(
          style = "width: 15%; float: left; overflow: hidden;",
          bucket_list(
            header = NULL,
            class = c("default-sortable","custom-sortable" ),
            orientation = c("vertical"),
            add_rank_list(
              text = NULL,
              labels = 100,
              options = sortable_options(disabled = T)
            ),
            add_rank_list(
              text = NULL,
              labels = c(50,40,30,15),
              options = sortable_options(disabled = T)
            )
          )
        ),

        div(
          style = "width: 15%; float: left; overflow: hidden;",
          bucket_list(
            header = NULL,
            class = c("default-sortable", "custom-sortable"),
            orientation = c("vertical"),
            add_rank_list(
              text = NULL,
              labels = c("Fixed"),
              options = sortable_options(disabled = T)
            ),
            add_rank_list(
              text = NULL,
              labels = c("Camp", rep("No Info",3)),
              options = sortable_options(disabled = F)
            )
          )
        )
        
      )
    })
  }
 )
}
shinyApp(ui, server)

Solution

  • You can specify custom handlers which do the magic:

    css <- HTML("
    .bucket-list-container .default-sortable .rank-list .highlight-marker {
       background-color: red;
    }
    
    .bucket-list-container .default-sortable .rank-list .highlight-marker:hover:not(.disabled)  {
       background-color: red;
    }
    
    .sortable-container {
       width: 15%; 
       float: left; 
       overflow: hidden;   
    }")
    
    js <- HTML("
       function init() {
          const pos = $('#camp_container .rank-list-container:nth(1) .rank-list-item span').index('#camp');
          $('#camp').parent().addClass('highlight-marker');
          $('#clone_container .rank-list-container:nth(1) .rank-list-item').eq(pos).addClass('highlight-marker');
       }
       
       function move_handler(evt) {
          const $elem = $(evt.item);
          if ($elem.has('#camp').length) {
             const $old = $('#clone_container .rank-list-container:nth(1) .rank-list-item').eq(evt.oldIndex);
             const $new = $('#clone_container .rank-list-container:nth(1) .rank-list-item').eq(evt.newIndex);
             $old.removeClass('highlight-marker');
             $new.addClass('highlight-marker');
          }
       }
    ")
    
    ui <- fluidPage(
       singleton(tags$head(tags$style(css))),
       singleton(tags$head(tags$script(js, type = "text/javascript"))),
       actionButton("run", "Run!"),
       uiOutput("container")
    )
    
    server <- function(input, output, session) {
       output$container <- renderUI({
          req(input$run)
          bucket_1 <- bucket_list(
             header = NULL,
             add_rank_list(
                text = NULL,
                labels = 100,
                options = sortable_options(disabled = TRUE)
             ),
             add_rank_list(
                text = NULL,
                labels = c(50, 40, 30, 15),
                options = sortable_options(disabled = TRUE)
             ),
             class = c("default-sortable","custom-sortable"),
             orientation = "vertical"
          )
          
          bucket_2 <- bucket_list(
             header = NULL,
             add_rank_list(
                text = NULL,
                labels = "Fixed",
                options = sortable_options(disabled = TRUE)
             ),
             add_rank_list(
                text = NULL,
                labels = c(list(span("Camp", id = "camp")), 
                           rep(list(span("No Info")), 3L)),
                options = sortable_options(disabled = FALSE, 
                                           onSort = "move_handler",
                                           onLoad = "init"
                )
             ),
             class = c("default-sortable","custom-sortable" ),
             orientation = "vertical")
          
          container_1 <- div(
             class = "sortable-container",
             id = "clone_container",
             bucket_1
          )
          container_2 <- div(
             class = "sortable-container",
             id = "camp_container",
             bucket_2
          )
          tagList(container_1,
                  container_2)
       })
    }
    
    shinyApp(ui, server)
    

    The CSS selectors and the marker class are quick and dirty and you can improve them, but you get the gist.


    Update