添加元素后触发 JavaScript 代码

Fire JavaScript code once element is added

假设我想在 shiny 中获得以下 jstree (带有按钮的部分只是为了说明 shinytree 从一开始就不存在):

$(function() {
  $('#create').on('click', function() {
    $('#mytree').jstree({
      'core' : {
        'data' : {
          "url" : "//www.jstree.com/fiddle/?lazy",
          "data" : function (node) {
            return { "id" : node.id };
          }
        }
      },
      contextmenu : {
        items : {
          'item1' : {
            'label' : 'item1',
            'action' : function () { /* action */ }
          }
        }
      },
      plugins : ["contextmenu"]
    });
  })
})
<link href="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.3.8/themes/default/style.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.3.8/jstree.min.js"></script>

<div id="mytree"></div>
<button id = "create">
   Create Tree
</button>

问题是我无法通过 shinyTree 提供 contextmenu。所以我需要回退到 JavaScript 来自己添加这个功能。在控制台上,我会这样做:

$('#mytree').jstree(true).settings.contextmenu = {
   items: {
      item1 : {
         'label' : 'item1',
         'action': function() { /* action */ }
      }
   }
}

但是我应该在我的 ShinyApp 中何时何地调用它?我使用另一个处理程序的方法不起作用,因为我猜想处理程序在渲染树之前触发(然后第二次按下按钮就可以了,至少表明 JS 代码按预期工作)。使用优先级也无济于事。

我可以使用一个 javascript 事件处理程序,我将附加到 $(document),它监听树的创建吗?

ShinyApp

library(shiny)
library(shinyTree)
library(shinyjs)
js_code <- "$('#mytree').jstree(true).settings.contextmenu = {
   items: {
      item1 : {
         'label' : 'item1',
         'action': function() { /* action */ }
      }
   }
};"
ui <- fluidPage(useShinyjs(),
                actionButton("create", "Create Tree"), 
                shinyTree("mytree", contextmenu = TRUE))

server <- function(input, output, session) {
   ## does not work as intended
   observeEvent(input$create, runjs(js_code), ignoreInit = TRUE, priority = -1)


   output$mytree <- renderTree({
     req(input$create)
     list("Root Node" = list("Child Node 1" = list(
                                                "Child Node 3" = "", 
                                                "Child Node 4" = ""),
                             "Child Node 2" = ""))
   }) 
}

shinyApp(ui, server)

我找到了解决方案。基本上可以使用 ready.jstreeloaded.jstree 事件:

library(shiny)
library(shinyTree)
library(shinyjs)
js_code <- "$('.shiny-tree').on('ready.jstree', function() {
   $(this).jstree(true).settings.contextmenu = {
      items: {
         item1 : {
            'label' : 'item1',
            'action': function() { /* action */ }
         }
      }
   };
})"
ui <- fluidPage(useShinyjs(),
                actionButton("create", "Create Tree"), 
                shinyTree("mytree", contextmenu = TRUE))

server <- function(input, output, session) {
   session$onFlushed(function() runjs(js_code))

   output$mytree <- renderTree({
     req(input$create)
     list("Root Node" = list("Child Node 1" = list(
                                                "Child Node 3" = "", 
                                                "Child Node 4" = ""),
                             "Child Node 2" = ""))
   }) 
}

shinyApp(ui, server)