Error in init.ts when using jsTreeR's grid parameter

57 Views Asked by At

I've already raised the issue here and here. By now a workaround exists however, I still don't understand the root cause.

When running the following app using the latest CRAN version of library(shiny) and library(jsTreeR) (2.5.0) after resizing the browser window this error can be seen in the browser console:

image

Example app:

library(jsTreeR)
library(shiny)

nodes <- list(
  list(
    text = "Fruits",
    type = "fruit",
    children = list(
      list(
        text = "Apple",
        type = "fruit",
        data = list(
          quantity = 20
        )
      ),
      list(
        text = "Banana",
        type = "fruit",
        data = list(
          quantity = 31
        )
      ),
      list(
        text = "Grapes",
        type = "fruit",
        data = list(
          quantity = 34
        )
      )
    ),
    state = list(
      opened = TRUE
    )
  )
)

grid <- list(
  columns = list(
    list(
      width = 200,
      header = "Product"
    ),
    list(
      width = 150,
      value = "quantity",
      header = "Quantity"
    )
  )
)

ui <-   fluidPage(
  titlePanel("jsTree grid"),
  jstreeOutput("jstree")
)

server <-   function(input, output, session){
  output$jstree <- renderJstree(jstree(nodes, search = TRUE, grid = grid))
}

shinyApp(ui, server)

This is only the case when jstree is provided with the grid parameter.

@StéphaneLaurent identified that the class shiny-bound-output is assigned to the jstree-grid-wrapper div which causes the issue and that removing it prevents the error.

I'd like to understand why this class is added in the first place and if there is a proper way to implement the grid parameter without running into this issue.

1

There are 1 best solutions below

0
Stéphane Laurent On BEST ANSWER

I think the answer is in the file jstreegrid.js, in the listener of the ready.jstree event, code starting at line 493:

.on(
  "ready.jstree",
  $.proxy(function (e, data) {
    // find the line-height of the first known node
    var anchorHeight = this.element
        .find("[class~='jstree-anchor']:first")
        .outerHeight(),
      q,
      cls = this.element.attr("class") || "";
    $(
      '<style type="text/css">div.jstree-grid-cell-root-' +
        this.rootid +
        " {line-height: " +
        anchorHeight +
        "px; height: " +
        anchorHeight +
        "px;}</style>"
    ).appendTo("head");

    // add container classes to the wrapper - EXCEPT those that are added by jstree, i.e. "jstree" and "jstree-*"
    q = cls.split(/\s+/).map(function (i) {
      var match = i.match(/^jstree(-|$)/);
      return match ? "" : i;
    });
    this.gridWrapper.addClass(q.join(" "));
  }, this)
);

In this code, cls = this.element.attr("class") is the character string made of all classes attributed to the tree, separated by a white space. Then q = cls.split(/\s+/).map(... is the array of all these classes except the jstree class and the classes started with jstree-, and these classes are then added to the grid (the jstree-grid-wrapper div). And then I see two possibilities:

  • at this stage, the tree already has the shiny-bound-output class, which is then added to the grid;

  • or the tree does not have the shiny-bound-output class yet, but it has the class jstreer, and then htmlwidgets adds the class shiny-bound-output to all elements having the jstreer class.


Edit

I've just checked, and the tree has both classes shiny-bound-output and jstreer at this stage.

A possible solution is to modify jstreegrid.js so that it does not copy these classes to the grid. In fact I don't see any other solution.