在很多网站上,您都有一个拖放界面来更改列表中元素的顺序。我正在寻找类似Shiny的东西。我希望用户能够拖放列表的元素以通过更改顺序来更改优先级。
现在我有一个滥用selectizeInput()
的解决方案。这有效,但当选择列表变大时,它很快变得很麻烦。
举例说明:
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])
})
}
)
缺点:要更改列表末尾的顺序,用户必须以正确的顺序选择整个列表。一个错误,他必须重新开始。
愿望清单:一个闪亮的小部件(可能来自另一个包),最好是拖放,这可以使这种动作更方便。
你可以使用custom input object来做到这一点。有很多库可以做到这一点,这是this one的一个例子。
以下是javascript中的闪亮绑定代码,需要包含在您应用的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。
我的app目录如下:
<application-dir>
|-- www
|-- sortableList.js
|-- app.R
我使用runApp("application-dir")
启动应用程序。
您还可以使用Shiny htmlwidget
小部件:listviewer,它支持开箱即用的可编辑和可排序列表。