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)
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.
CSS
such that we do not need !important
if
clause in the JS
to make sure it fires only for the element containing #camp
.init
function such that the code will also work, if Camp
is not in the first position.