javascriptrshinyjstreer

How to remove the option for the user to collapse a specified parent node in jsTreeR?


Any recommendations for how to make only specific nodes in package jsTreeR non-collapsible, while all other nodes remain collapsible as illustrated below? The code is posted beneath the illustration.

enter image description here

Code:

library(jsTreeR)
library(shiny)

nodes <- list(
  list(
    text = "Menu",
    state = list(opened = TRUE),
    children = list(
      list(text = "Dog",type = "moveable",state = list(disabled = TRUE)),
      list(text = "Cat",type = "moveable",state = list(disabled = TRUE))
    )
  ),
  list(text = ">> Drag here <<",type = "target",state = list(opened = TRUE))
)

dnd <- list(
  always_copy = TRUE,
  inside_pos = "last", 
  is_draggable = JS(
    "function(node) {",
    "  return node[0].type === 'moveable';",
    "}"
  )
)

mytree <- jstree(
  nodes, dragAndDrop = TRUE, dnd = dnd,
  types = list(moveable = list(), target = list())
)

ui <- fluidPage(
  # tags$head(tags$script(HTML(script))),
  fluidRow(jstreeOutput("mytree"))
)

server <- function(input, output, session){output[["mytree"]] <- renderJstree(mytree)}

shinyApp(ui, server)

Solution

  • I would add a direct click handler to the first <i> node, which uses stopPropagation to prevent the click event to bubbling up and thus closing the parent. You need to delay the assignment of the click handler, b/c at render time the nodes (and thus the <i> element with the arrow) are not yet set up. An outer one handler fires, when the nodes are ready and that’s where we assign the click handler.

    mytree %>%
       htmlwidgets::onRender("
          function (el) {
             $(el).one('ready.jstree', function() { 
                 // need to wait until all nodes are loaded to assigne event listener
                 $(this).find('i').first().on('click', (evt) => evt.stopPropagation()) 
             });
          }")