【问题标题】:Shiny widget to change the order of elements in a vector用于更改向量中元素顺序的闪亮小部件
【发布时间】:2017-03-22 11:18:24
【问题描述】:

在很多网站上,您都有一个拖放界面来更改列表中元素的顺序。我在 Shiny 中寻找类似的东西。我希望用户能够拖放列表的元素以通过更改顺序来更改优先级。

现在我有一个滥用selectizeInput() 的解决方案。 This works, but it quickly becomes cumbersome when the list of choices becomes larger.

插图:

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])
    })
  }
)

缺点:要更改列表末尾的顺序,用户必须以正确的顺序选择整个列表。一个错误,他必须重新开始。

Wishlist:一个闪亮的小部件(可能来自另一个包),最好是拖放,可以使这种操作更方便。

【问题讨论】:

    标签: r drag-and-drop shiny


    【解决方案1】:

    您可以使用custom input object 来执行此操作。有很多库可以做到这一点,这里有一个 this one 的例子。

    以下是 JavaScript 中的 Shiny 绑定代码,需要包含在您应用的 www 文件夹中:

    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);
    

    它非常小,它在初始化时创建 Sortable 实例,并在用户使用库的 onUpdate 事件更改元素时返回元素的顺序。

    这是一个使用 R 代码创建元素的示例应用:

    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)
    

    sortableList 函数包括 Sortable 库和带有 Shiny 绑定代码的 sortableList.js,并创建包含传递给 value 的向量值的 div。

    我的应用目录如下:

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

    我使用runApp("application-dir") 启动应用程序。

    【讨论】:

    • 太棒了,这很好用。我真的应该多学习一两件事关于 Javascript :-)
    【解决方案2】:

    为了后代;现在由 Rstudio 的 sortable 包处理。

    【讨论】:

    • 谢谢小费。这是一个正在开发的实验包,所以我会感兴趣地关注它,但暂时不要在生产中使用它。
    【解决方案3】:

    您还可以使用Shiny htmlwidget 小部件:listviewer,它支持可编辑和可排序开箱即用的列表。

    【讨论】:

      猜你喜欢
      • 2021-11-04
      • 1970-01-01
      • 2015-10-10
      • 2021-01-09
      • 2019-12-31
      • 2015-03-05
      • 2020-12-16
      • 1970-01-01
      • 2015-10-02
      相关资源
      最近更新 更多