emillykkejensen / ShinyTreeMenu

ShinyTreeMenu provides a clean tree menu UI useing only HTML and CSS, with lazy loading making it posible to build enormous tree menus.
GNU General Public License v3.0
1 stars 1 forks source link

how open/close branches, and activate links from server side #3

Open sorhawell opened 5 years ago

sorhawell commented 5 years ago

Hi Emil thanks for this lovely ShinyTreeMenu!!

I feel the documentation do not explain around how to open/close and activate tree links from server side. I have attempted to do so with shinyjs::runjs(js_string2) however I see no visual change on client side.

The overall goal would be to manipulate the tree from somewhere else in a shiny app. what am I missing?

best Soren

library(ShinyTreeMenu)

shinyApp(

  ui = fluidPage(
    # ShinyTreeMenu uses shinyjs - so remember to include shinyjs in your UI
    shinyjs::useShinyjs(),
    actionButton("actionman","tryk mig"),
    ShinyTreeMenuOutput("treemenu")
  ),

  server = function(input, output, session) {

    # Treedata has to be in the form of a reactive expression
    treedata <- reactive({
      ShinyTreeMenu::treetestdata
    })

    # Use the shiny callModule to render the ShinyTreeMenu
    # Note that you should not include () when adding your reactive treedata
    shiny::callModule(ShinyTreeMenu::renderShinyTreeMenu,
                      id = "treemenu",
                      treedata = treedata,
                      level_icons = "tree")

    # Here you will update the ShinyTreeMenu
    # As with the render function, you should not include () when adding your reactive treedata
    ShinyTreeMenu::updateShinyTreeMenu(
      treedata = treedata,
      treemenu_open = reactive({input$treemenu_open}),
      level_icons = "tree")

    # For the purpose of displaying the selection functionality
    observeEvent(input$treemenu, {
      showModal(
        modalDialog(
          paste("Selected id:", input$treemenu$val,
                "| Selected level:", input$treemenu$level,
                "| Selected row:", input$treemenu$row)
        )
      )
    })

    observe(print(input$actionman))
    observeEvent(input$actionman ,ignoreInit = FALSE,{
      print("try update")
      js_string = paste0("javascript:Shiny.setInputValue('treemenu_open', {openid:'",input$actionman,"', randomVal:Math.random()});")
      js_string2 = "javascript:Shiny.setInputValue('treemenu_open', {openid:'1', randomVal:Math.random()});"
      print(js_string2)
      shinyjs::runjs(js_string2) 
    })

    observe({print("input$treemenu_open is ...."); str(input$treemenu_open)})

  }

)
sorhawell commented 5 years ago

I come somewhat closer. I can close menus. In this case if sub-sub branches of branch1 is open. I can close the sub branches by pressing the button. It is ofc not the overall intention to control via a button, but it would be an example of server side control of ShinyTreeMenu

How do I choose if to open or close a menu. How does shinyTreeMenu store the current state of open close?


#new update that do not care if treemenu_open input is reactive or absolute
newupdateShinyTreeMenu <- function(treedata, treemenu_open, level_icons) {
  print("evalute reactiveness")
  td = if(inherits(treemenu_open,"reactive")) {
    print("try reactive")
    print(class(treemenu_open))
    treemenu_open()
  } else{ 
    print("try non-reactive")
    print(class(treemenu_open))
    treemenu_open
  }

  shiny::observeEvent(td, {
    shinyjs::html(id = paste0("treemenu_open_", td$openid),
                  html =
                    ShinyTreeMenu:: ShinyTreeMenuHTML(
                      treedata = treedata(),
                      select_id = td$openid,
                      level_icons = level_icons))
  })
}

  if (interactive()) {
    global_i = 1
    shinyApp(

      ui = fluidPage(

        # ShinyTreeMenu uses shinyjs - so remember to include shinyjs in your UI
        shinyjs::useShinyjs(),
        actionButton("abot","press me"),
        ShinyTreeMenuOutput("treemenu")
      ),

      server = function(input, output, session) {

        # Treedata has to be in the form of a reactive expression
        treedata <- reactive({
          td = ShinyTreeMenu::treetestdata
          #print(td)
          td
        })

        ##Here is the actual suggestion
        observeEvent(input$abot,ignoreInit = TRUE,{
          print("sending js script")
          #runjs("var today = new Date(); alert(today);")
          #shinyjs::runjs("Shiny.setInputValue('treemenu_open', {openid:'1', randomVal:Math.random()});")
          newupdateShinyTreeMenu(treedata,treemenu_open = list(openid="1",randomVal=runif(1)),level_icons = "tree")
        })

        # Use the shiny callModule to render the ShinyTreeMenu
        # Note that you should not include () when adding your reactive treedata
        shiny::callModule(ShinyTreeMenu::renderShinyTreeMenu,
                          id = "treemenu",
                          treedata = treedata,
                          level_icons = "plus")

        #print what open id is before and after update
        r_treemenu_open = reactive({
          tm_o = input$treemenu_open
          global_i <<- global_i + 1
          print(global_i)
          print(tm_o)
          tm_o

        })
        observe({
          cat("tm_o:",unlist(r_treemenu_open()),"   global_i ",global_i)
        })

        # Here you will update the ShinyTreeMenu
        # As with the render function, you should not include () when adding your reactive treedata
        ShinyTreeMenu:: updateShinyTreeMenu(
          treedata = treedata,
          treemenu_open = r_treemenu_open,
          level_icons = "plus")

        # For the purpose of displaying the selection functionality
        observeEvent(input$treemenu, {
          showModal(
            modalDialog(
              paste("Selected id:", input$treemenu$val,
                    "| Selected level:", input$treemenu$level,
                    "| Selected row:", input$treemenu$row)
            )
          )
        })

      }

    )

  }
sorhawell commented 5 years ago

ok realize that control of hiding/showing branches and subbranches is client side HTML / CSS only.

e.g. /inst/www/shinyTreeMenu.css

ol.tree li input:checked ol{
  height:auto;
}

ol.tree li input:checked ol > li{
  display:block;
  margin:0 0 0.1em 0;
}

the generated check boxes...

<input type="checkbox" id="1" onclick="javascript:Shiny.setInputValue('treemenu_open', {openid:'1', randomVal:Math.random()});" class="shiny-bound-input">

There is no function in shinyTreeMenu yet, that can open/close branches from server side.

I suppose the most clean solution would be to make a function that takes a selected branch as input and send a javascript-snippet to be evaluated on client side. The javascript code should emulate the user has clicked one specific checkbox. Then all other server/client interactions could proceed as normal.

stack-overflow discussion of checking unchecking HTML boxes

emillykkejensen commented 5 years ago

Sorry for not getting back to you before now...

But can see you figured it out yourself and no, you can directly open/close menus from shiny/server side.

The way to do that would probably be using shinyJS to click (shinyjs::click()) the checkbox you would want to open – and if it is a nested menu item, then adding a loop to it.

That ought to work…

Let me know how it goes? 😊