JdeMello
JdeMello

Reputation: 1718

Using values selected from a javascript based select menu in shiny

I am using the jQuery plugin ComboTree to display a tree-like select menu in my shiny app.enter image description here

I am having trouble retrieving those values (e.g. c("Item 2", "Item 2-1")) to use in some output. So the issue here is to retrieve whatever values are selected from the select menu ($("example").val();).

ui.r:

ui <- function(){
  fluidPage(
    tags$head(
      tags$script(src = "comboTreePlugin.js"), 
      tags$script(src = "icontains.js"), 
      tags$link(rel = "stylesheet", type = "text/css", href = "comboTreeStyle.css")
    ),
    includeScript("myData.json"),
    # layouy content ----
    sidebarLayout(
      sidebarPanel(width = 3,
                   tags$input(type = "text", id = "example", placeholder = "Select"), 
                   uiOutput("comboTreeMenu")
      ), 
      mainPanel(width = 9)
    )
  ) 
}

server.r:

server <- function(input, output, session){
  output$comboTreeMenu <- renderUI({
    includeScript("www/example.js")
    })

  # want to do some manipulation with the resulting selections from the 
  # combo tree. Something along the lines of:

  # selections <- eventReactive(input$click, {
  #   return(input$comboTreeSelections)
  # })
}

example.js:

comboTree1 = $('#example').comboTree({
  source: myData,
  isMultiple: true
});

myData.json:

var myData = [
  {
    id: 0,
    title: 'Item 1 '
  }, {
    id: 1,
    title: 'Item 2',
    subs: [
      {
        id: 10,
        title: 'Item 2-1'
      }, {
        id: 11,
        title: 'Item 2-2'
      }, {
        id: 12,
        title: 'Item 2-3'
      }
      ]
  }, {
    id: 2,
    title: 'Item 3'
  }
  ];

I've tried to add an extra piece of js script like so:

selectedValues = $("#example").val();

Shiny.onInputChange("comboTreeSelections", selectedValues);

Thank you!

Upvotes: 2

Views: 1165

Answers (2)

SeGa
SeGa

Reputation: 9809

This is just a quick fix, as I don't really recommend using a pure jQuery plugin, since you will have to write all the interaction between combotree and Shiny yourself. But when you're only interested in the actual selected items, you could do this:

In comboTreePlugin.js change the function at line 129 to:

this._elemItemsTitle.on('click', function(e){
    e.stopPropagation();
    if (_this.options.isMultiple)
        _this.multiItemClick(this);
    else
        _this.singleItemClick(this);

    var selItem = comboTree1.getSelectedItemsTitle();
    Shiny.onInputChange('selTitle', selItem);
});

This example will only work, when you really click on an item, it wont fire when you select an item by hitting Enter. You would have to copy/paste the last 2 lines above in the keydown-event handler (code 13).

Then you can access the variable selTitle with input$selTitle in Shiny.


Here's a small ShinyApp which prints out the selected titles:

library(shiny)

ui <- {fluidPage(
    tags$head(
      tags$script(src = "comboTreePlugin.js"), 
      tags$script(src = "icontains.js"), 
      tags$link(rel = "stylesheet", type = "text/css", href = "comboTreeStyle.css")
    ),
    includeScript("www/myData.json"),
    sidebarLayout(
      sidebarPanel(width = 3,
                   tags$input(type = "text", id = "example", placeholder = "Select"), 
                   uiOutput("comboTreeMenu"),
                   verbatimTextOutput("selected")
      ), 
      mainPanel(width = 9)
    )
)}

server <- function(input, output, session){
  output$comboTreeMenu <- renderUI({
    includeScript("www/example.js")
  })

  output$selected <- renderPrint({
    req(input$selTitle)
    print(input$selTitle)
  })
}

shinyApp(ui, server)

Upvotes: 1

SeGa
SeGa

Reputation: 9809

I found another method, where you dont have to mess with the source code and just inject some javascript. This will trigger a setInterval function, when the dropdown is visible/openend and will re-run every 500ms.

library(shiny)

js <- HTML("
$(function() {
  var selection = setInterval(function() {
    if($('.comboTreeDropDownContainer').is(':visible')) {
      var selItem = comboTree1.getSelectedItemsTitle();
      Shiny.onInputChange('selTitle', selItem)
    }
  }, 500);
});
")

ui <- {fluidPage(
    tags$head(
      tags$script(src = "comboTreePlugin.js"), 
      tags$script(src = "icontains.js"), 
      tags$script(js),
      tags$link(rel = "stylesheet", type = "text/css", href = "comboTreeStyle.css")
    ),
    includeScript("www/myData.json"),
    sidebarLayout(
      sidebarPanel(width = 3,
                   tags$input(type = "text", id = "example", placeholder = "Select"), 
                   uiOutput("comboTreeMenu"),
                   verbatimTextOutput("selected")
      ), 
      mainPanel(width = 9)
    )
)}

server <- function(input, output, session){
  output$comboTreeMenu <- renderUI({
    includeScript("www/example.js")
  })

  output$selected <- renderPrint({
    req(input$selTitle)
    print(input$selTitle)
  })
}

shinyApp(ui, server)

Upvotes: 1

Related Questions