Shiny widget for reordering elements in a vector

On multiple sites, you have a drag and drop interface to reorder items in a list. I'm looking for something similar in Shiny. I want the user to be able to drag the list items to change the priority by changing the order.

I now have a solution that is abusing selectizeInput()

. It works, but it quickly becomes cumbersome as the list of options gets bigger.

Illustration:

library(shiny)

shinyApp(
  ui = shinyUI({
    fluidPage(
      title = "Example for ordering objects",
      sidebarLayout(
        sidebarPanel(uiOutput("selection"),
                     actionButton('update',"Update")),
        mainPanel(
          helpText('The order of elements'),
          tableOutput('theorder')
        )
      )
    )
  }),
  server = function(input, output, session) {
    values <- reactiveValues(x = c('Item1','Item2','Item3'))

    output$selection <- renderUI({
      selectizeInput('neworder',
                     'Select new order',
                     choices = values$x,
                     multiple = TRUE)
    })

    output$theorder <- renderTable(
      values$x
    )

    observeEvent(input$update,{
      id <- values$x %in% input$neworder
      values$x <- c(input$neworder, values$x[!id])
    })
  }
)

      

Down side. To change the order at the end of the list, the user must select the entire list in the correct order. One mistake and he must start over.

Wishlist: shiny widget (possibly from another package), drag and drop desirable, which might make this action more convenient.

+3


source to share


3 answers


You can use a custom input object for this . There are a bunch of libraries for this, here is an example from this one .

Here is a flamboyant binding code in javascript to be included in www

your application folder :

sortableList.js

var sortableListBinding = new Shiny.InputBinding();
$.extend(sortableListBinding, {
  find: function(scope) {
    return $(scope).find(".sortableList");
  },
  getValue: function(el) {
    if (typeof Sortable.active != 'undefined'){
      return Sortable.active.toArray();
    }
    else return "";
  },
  subscribe: function(el, callback) {
    $(el).on("change.sortableListBinding", function(e) {
      callback();
    });
  },
  unsubscribe: function(el) {
    $(el).off(".sortableListBinding");
  },
  initialize: function(el) {
    Sortable.create(el,{
      onUpdate: function (evt) {
          $(el).trigger("change");
    }});
  }
});

Shiny.inputBindings.register(sortableListBinding);

      

It's very minimal, it creates a Sortable instance on initialization and returns the order of the items whenever the user changes them using the onUpdate

library event .

Here's an example app with R code to create an item:



app.R

library(shiny)
library(htmlwidgets)

sortableList <- function(inputId, value) {
  tagList(
    singleton(tags$head(tags$script(src="http://rubaxa.github.io/Sortable/Sortable.js"))),
    singleton(tags$head(tags$script(src = "sortableList.js"))),
    tags$div(id = inputId,class = "sortableList list-group",
             tagList(sapply(value,function(x){
               tags$div(class="list-group-item","data-id"=x,x)
             },simplify = F)))
  )
}

ui <- fluidPage(
  sortableList('sortable_list',c(2,3,4)),
  sortableList('sortable_list2',c(5,6,7)),
  textOutput('test'),
  textOutput('test2')
)

server <- function(input, output, session) 
{
 output$test <- renderText({input$sortable_list})
 output$test2 <- renderText({input$sortable_list2})
 }

shinyApp(ui=ui, server=server)

      

The function sortableList

includes both the library Sortable

and sortableList.js

Shiny glue code and creates divs holding the values ​​of the vector passed to value

.

My app directory looks like this:

<application-dir>
|-- www
    |-- sortableList.js
|-- app.R

      

And I am using runApp("application-dir")

to run the application.

+6


source


For posterity; this is now handled by the sortable package from Rstudio.



+1


source


You can also use the Shiny htmlwidget

: listviewer widget which supports editable and sortable .

-1


source







All Articles