jsTreeR icon indicating copy to clipboard operation
jsTreeR copied to clipboard

jsTree not updating when using `uiOutput()`

Open Jeff-Thompson12 opened this issue 11 months ago • 9 comments

Here is a minimal example of the behavior. If the jstree output is created using renderUI() in the server, the updating of the tree does not work as expected. (Sidenote: I do not know why the second Root folder is not showing in my example either.)

library(shiny)
library(jsTreeR)

nodes1 <- list(
  list(
    text = "Root1A",
    children = list(
      list(text = "Child1A1")
    )
  ),
  list(
    text = "Root1B",
    children = list(
      list(text = "Child1B1"),
      list(text = "Child1B2")
    )
  )
)

nodes2 <- list(
  list(
    text = "Root2A",
    children = list(
      list(text = "Child2A1"),
      list(text = "Child2A2")
    )
  ),
  list(
    text = "Root2B",
    children = list(
      list(text = "Child2B1")
    )
  )
)

ui <- fluidPage(
  selectInput("node_select", "Select Node List", list("Node 1" = "n1", "Node 2" = "n2")),
  jstreeOutput("dirtree1"),
  uiOutput("dirtree2_ui")
)

server <- function(input, output, session) {
  nodes <- reactiveVal(list())
  
  observeEvent(input$node_select, nodes(ifelse(input$node_select == "n1", nodes1, nodes2)))
  
  output$dirtree2_ui <- renderUI({
    tagList(
      h2(paste("You have selected", input$node_select)),
      jstreeOutput("dirtree2")
    )
  })
  
  output$dirtree1 <- renderJstree(jstree(isolate(nodes())))
  output$dirtree2 <- renderJstree(jstree(isolate(nodes())))
  
  observeEvent(nodes(), {
    jsTreeR::jstreeUpdate(session, "dirtree1", nodes())
    jsTreeR::jstreeUpdate(session, "dirtree2", nodes())
  }, ignoreInit = TRUE)
}

shinyApp(ui, server)

BDDC2F2F-CD86-4127-8011-5A9B683DC332

Jeff-Thompson12 avatar Jul 19 '23 14:07 Jeff-Thompson12

Don't use ifelse for lists. Do:

  observeEvent(
    input$node_select, 
    nodes(if(input$node_select == "n1") nodes1 else nodes2)
  )

and the second child will appear as expected.

I'm working on the other issue.

stla avatar Jul 19 '23 15:07 stla

Not sure why but it works if you comment a line:

  output$dirtree2_ui <- renderUI({
    tagList(
      #h2(paste("You have selected", input$node_select)),
      jstreeOutput("dirtree2")
    )
  })

stla avatar Jul 19 '23 15:07 stla

If you comment that line it won't re-render when input$node_select is changed. If you insert a browser(), you will see it doesn't trigger if you comment out that line when changing the input.

Jeff-Thompson12 avatar Jul 19 '23 15:07 Jeff-Thompson12

No, it works, because there is jstreeUpdate. I tested and it works.

stla avatar Jul 19 '23 15:07 stla

Try this

output$dirtree2_ui <- renderUI({
  input$node_select
  tagList(
    jstreeOutput("dirtree2")
  )
})

It removes the h2() element but still triggers renderUI() whenever input$node_select is changed. This causes it to break.

Jeff-Thompson12 avatar Jul 19 '23 15:07 Jeff-Thompson12

But don't do this, this is the cause of the problem.

stla avatar Jul 19 '23 15:07 stla

When input$node_select changes, then nodes changes, and the observer is triggered, which triggers the jsTreeUpdate.

stla avatar Jul 19 '23 15:07 stla

Maybe this example using {shinyTree} will highlight the problem. I would not expect different behavior if using renderUI(). My point is that this situation is producing unexpected behavior.

library(shiny)
library(jsTreeR)
library(shinyTree)

nodes1 <- list(
  list(
    text = "Root1A",
    children = list(
      list(text = "Child1A1")
    )
  ),
  list(
    text = "Root1B",
    children = list(
      list(text = "Child1B1"),
      list(text = "Child1B2")
    )
  )
)

nodes2 <- list(
  list(
    text = "Root2A",
    children = list(
      list(text = "Child2A1"),
      list(text = "Child2A2")
    )
  ),
  list(
    text = "Root2B",
    children = list(
      list(text = "Child2B1")
    )
  )
)

nodes3 <- list(
  Root1A = list(Child1A1 = ""),
  Root1B = list(Child1B1 = "", Child1B2 = "")
)

nodes4 <- list(
  Root2A = list(Child2A1 = "", Child2A2 = ""),
  Root2B = list(Child2B1 = "")
)

ui <- fluidPage(
  selectInput("node_select", "Select Node List", list("Node 1" = "n1", "Node 2" = "n2")),
  column(
    6,
    jstreeOutput("dirtree1"),
    br(),
    uiOutput("dirtree2_ui")
  ),
  column(
    6,
    shinyTree("dirtree3"),
    br(),
    uiOutput("dirtree4_ui")
  )
)

server <- function(input, output, session) {
  nodes <- reactiveVal(list())
  shinyTree_nodes <- reactiveVal(list())
  
  observeEvent(input$node_select, {
    nodes(if (input$node_select == "n1") nodes1 else nodes2)
    shinyTree_nodes(if (input$node_select == "n1") nodes3 else nodes4)
    })
  
  output$dirtree2_ui <- renderUI({
    input$node_select
    tagList(
      jstreeOutput("dirtree2")
    )
  })
  output$dirtree4_ui <- renderUI({
    input$node_select
    tagList(
      shinyTree("dirtree4")
    )
  })
  
  output$dirtree1 <- renderJstree(jstree(isolate(nodes())))
  output$dirtree2 <- renderJstree(jstree(isolate(nodes())))
  output$dirtree3 <- renderTree(isolate(shinyTree_nodes()))
  output$dirtree4 <- renderTree(isolate(shinyTree_nodes()))
  
  observeEvent(nodes(), {
    jstreeUpdate(session, "dirtree1", nodes())
    jstreeUpdate(session, "dirtree2", nodes())
    updateTree(session, "dirtree3", shinyTree_nodes())
    updateTree(session, "dirtree4", shinyTree_nodes())
  }, ignoreInit = TRUE)
}

shinyApp(ui, server)

Jeff-Thompson12 avatar Jul 19 '23 15:07 Jeff-Thompson12

I agree it's strange but that's the way it works. My code for the updating is the same as the one of shinyTree.

Another solution is to remove isolate from isolate(nodes).

stla avatar Jul 19 '23 21:07 stla