Reputation: 20329
Let's assume I want to get the following jstree
in shiny
(the part with the button is just to illustrate that the shinytree
is not present from the beginning):
$(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>
The problem is that I cannot provide the contextmenu
via shinyTree
. So I need to fall back to JavaScript to add this functionality myself. On the console I would do it like follows:
$('#mytree').jstree(true).settings.contextmenu = {
items: {
item1 : {
'label' : 'item1',
'action': function() { /* action */ }
}
}
}
But where and when would I call that in my ShinyApp? My approach with another handler does not work, because I guess that the handler fires before the tree is rendered (a second press to the button does the trick then, showing at least that the JS code works as intended). Playing with the priority did not help either.
Could I use a javascript event handler which I would attach to $(document)
, which listens to the creation of the tree?
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)
Upvotes: 3
Views: 144
Reputation: 20329
I found the solution. Basically one can use the ready.jstree
or loaded.jstree
event:
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)
Upvotes: 1