如何使用库(jsTreeR)创建不可编辑的叶节点子集

How to create a subset of uneditable leaf nodes with library(jsTreeR)

提问人:ahnungslos 提问时间:3/13/2023 最后编辑:ahnungslos 更新时间:3/14/2023 访问量:601

问:

我想知道是否可以使用 {jsTreeR} 创建不可编辑的叶节点子集。

叶子的预期行为是,它们不能是:

  • 重 命名
  • 删除
  • 有自己的子节点

此外,如果分支节点有叶子,则不应删除它们。 但是,可以在分支节点或父节点之间拖放叶子。

我找到了该选项,但这似乎不会影响上下文菜单:state = list(disabled = TRUE)

library(jsTreeR)
library(shiny)

nodes <- list(
  list(
    text = "Branch 1",
    state = list(opened = TRUE, disabled = FALSE),
    type = "parent",
    children = list(
      list(text = "Leaf A", type = "child", state = list(disabled = TRUE), data = list(customdata = 1)),
      list(text = "Leaf B", type = "child", state = list(disabled = FALSE), data = list(customdata = 2)),
      list(text = "Leaf C", type = "child", state = list(disabled = FALSE), data = list(customdata = 3)),
      list(text = "Leaf D", type = "child", state = list(disabled = FALSE), data = list(customdata = 4))
    )
  ),
  list(text = "Branch 2", type = "parent", state = list(opened = TRUE))
)

ui <- fluidPage(
  jstreeOutput("jstree")
)

server <- function(input, output, session){
  output[["jstree"]] <- renderJstree({
    suppressMessages(jstree(
      nodes,
      search = list(
        show_only_matches = TRUE,
        case_sensitive = FALSE,
        search_leaves_only = FALSE
      ),
      dragAndDrop = TRUE,
      multiple = TRUE,
      contextMenu = TRUE,
      types = list(default = list(icon = "fa fa-caret-right"), child = list(icon = "fa-solid fa-leaf"), parent = list(icon = "fa-brands fa-pagelines")),
      theme = "proton"
    ))
  })
}  

shinyApp(ui, server)

任何提示都是值得赞赏的。


编辑:@StéphaneLaurent的方法包装在一个闪亮的应用程序中:

library(jsTreeR)
library(shiny)

nodes <- list(
  list(
    text = "Branch 1",
    state = list(opened = TRUE, disabled = FALSE),
    type = "parent",
    children = list(
      list(text = "Leaf A", type = "undeletable", state = list(disabled = FALSE), data = list(customdata = 1)),
      list(text = "Leaf B", type = "undeletable", state = list(disabled = FALSE), data = list(customdata = 2)),
      list(text = "Leaf C", type = "undeletable", state = list(disabled = FALSE), data = list(customdata = 3)),
      list(text = "Leaf D", type = "undeletable", state = list(disabled = FALSE), data = list(customdata = 4))
    )
  ),
  list(text = "Branch 2", type = "parent", state = list(opened = TRUE))
)

ui <- fluidPage(
  jstreeOutput("mytree")
)

customMenu <- JS(
  "function customMenu(node) {",
  "  var tree = $('#mytree').jstree(true);", # 'mytree' is the Shiny id or the elementId
  "  var items = {",
  "    'delete' : {",
  "      'label'  : 'Delete',",
  "      'action' : function (obj) { if(node.type !== 'undeletable') tree.delete_node(node); },",
  "      'icon'   : 'glyphicon glyphicon-trash'",
  "     }",
  "  }",
  "  return items;",
  "}")

server <- function(input, output, session){
  output[["mytree"]] <- renderJstree({
    suppressMessages(jstree(
      nodes,
      search = list(
        show_only_matches = TRUE,
        case_sensitive = FALSE,
        search_leaves_only = FALSE
      ),
      dragAndDrop = TRUE,
      multiple = TRUE,
      contextMenu = list(items = customMenu),
      types = list(default = list(icon = "fa fa-caret-right"), undeletable = list(icon = "fa-solid fa-leaf"), parent = list(icon = "fa-brands fa-pagelines")),
      theme = "proton"
    ))
  })
}  

shinyApp(ui, server)
JavaScript R 闪亮的 jstree jstreer

评论

0赞 ahnungslos 3/15/2023
可以在此处找到后续问题。

答:

2赞 Stéphane Laurent 3/13/2023 #1

您必须使用自定义上下文菜单。将类型分配给要不可删除的节点,并在自定义上下文菜单中使用它:

library(jsTreeR)

nodes <- list(
  list(
    text = "Menu",
    state = list(opened = TRUE),
    children = list(
      list(
        text = "this node cannot be deleted",
        type = "undeletable"
      ),
      list(
        text = "B"
      ),
      list(
        text = "C"
      )
    )
  ),
  list(
    text = "Drag here:",
    state = list(opened = TRUE)
  )
)

customMenu <- JS(
  "function customMenu(node) {",
  "  var tree = $('#mytree').jstree(true);", # 'mytree' is the Shiny id or the elementId
  "  var items = {",
  "    'delete' : {",
  "      'label'  : 'Delete',",
  "      'action' : function (obj) { if(node.type !== 'undeletable') tree.delete_node(node); },",
  "      'icon'   : 'glyphicon glyphicon-trash'",
  "     }",
  "  }",
  "  return items;",
  "}")

jstree(
  nodes,
  types = list(undeletable = list()),
  checkCallback = TRUE,
  contextMenu = list(items = customMenu),
  elementId = "mytree" # don't use elementId in Shiny! use the Shiny id
)

这是一个完整的上下文菜单,您必须按上述方式对其进行修改:

customMenu <- JS("function customMenu(node)
{
  var tree = $('#mytree').jstree(true);
  var items = {
    'rename' : {
      'label' : 'Rename',
      'action' : function (obj) { tree.edit(node); },
      'icon': 'glyphicon glyphicon-edit'
    },
    'delete' : {
      'label' : 'Delete',
      'action' : function (obj) { tree.delete_node(node); },
      'icon' : 'glyphicon glyphicon-trash'
    },
    'create' : {
      'label' : 'Create',
      'action' : function (obj) { tree.create_node(node); },
      'icon': 'glyphicon glyphicon-plus'
    }
  }
  return items;
}")

评论

0赞 ahnungslos 3/13/2023
出于某种原因,当我在闪亮的应用程序中运行它时,它似乎不起作用。请看我的编辑。
1赞 Stéphane Laurent 3/13/2023
@ahnungslos 你必须添加到论点中。undeletable = list()types
2赞 ismirsehregal 3/13/2023 #2

这是另一种方法(基于此处给出的答案),它禁用上下文菜单项,而不是在单击它们后不执行任何操作。

优点是,项目是灰色的。

以下还考虑了不允许删除具有叶节点的分支的问题:

library(jsTreeR)
library(shiny)

nodes <- list(
  list(
    text = "Branch 1",
    state = list(opened = TRUE, disabled = FALSE),
    type = "parent",
    children = list(
      list(text = "Leaf A", type = "undeletable", state = list(disabled = FALSE), data = list(customdata = 1)),
      list(text = "Leaf B", type = "undeletable", state = list(disabled = FALSE), data = list(customdata = 2)),
      list(text = "Leaf C", type = "undeletable", state = list(disabled = FALSE), data = list(customdata = 3)),
      list(text = "Leaf D", type = "undeletable", state = list(disabled = FALSE), data = list(customdata = 4))
    )
  ),
  list(text = "Branch 2", type = "parent", state = list(opened = TRUE))
)

ui <- fluidPage(
  jstreeOutput("mytree")
)

customMenu <- JS(
  "function customMenu(node) {
  var tree = $('#mytree').jstree(true);
  var items = {
    'rename' : {
      'label' : 'Rename',
      'action' : function (obj) { tree.edit(node); },
      'icon': 'glyphicon glyphicon-edit'
    },
    'delete' : {
      'label' : 'Delete',
      'action' : function (obj) { tree.delete_node(node); },
      'icon' : 'glyphicon glyphicon-trash'
    },
    'create' : {
      'label' : 'Create',
      'action' : function (obj) { tree.create_node(node); },
      'icon': 'glyphicon glyphicon-plus'
    }
  }
  
  if (node.children.length > 0) { items.delete._disabled = true; }
  if (node.type === 'undeletable') { items.rename._disabled = true;
                                     items.delete._disabled = true;
                                     items.create._disabled = true;
                                    }

  return items;
}")

server <- function(input, output, session){
  output[["mytree"]] <- renderJstree({
    suppressMessages(jstree(
      nodes,
      search = list(
        show_only_matches = TRUE,
        case_sensitive = FALSE,
        search_leaves_only = FALSE
      ),
      dragAndDrop = TRUE,
      multiple = TRUE,
      contextMenu = list(items = customMenu),
      types = list(default = list(icon = "fa fa-caret-right"), undeletable = list(icon = "fa-solid fa-leaf"), parent = list(icon = "fa-brands fa-pagelines")),
      theme = "proton"
    ))
  })
}  

shinyApp(ui, server)

评论

1赞 Stéphane Laurent 3/14/2023
凉!我会将其添加到包中的示例中。