搜索栏是任何流行的网站或应用程序中的一个常见功能。大多数网站在用户开始在搜索栏中输入信息时,就会实时显示建议。它极大地改善了用户体验,用户能够在网站上找到他/她想看到的内容。最近,在shiny仪表板上有这种类似的功能已经成为普遍的要求。在shiny中,搜索栏有很多变通方法,但没有直接的方法来实现它。
搜索栏(单选)
如果你希望用户不选择一个以上的值。这是为了防止从下拉菜单中进行多重选择。你可以使用multiple = FALSE 来选择单个项目。选项maxItems = '1' 移除默认显示在下拉菜单中的下拉图标。为了使selectizeInput 表现得像一个搜索栏,我们使用了onDropdownOpen 和onType 选项中提到的javascript。
在
choices参数中,我们使用了两个随机字母的连接。例如 "AB"。因为它是随机的,所以`AB`不一定存在于下拉菜单中:-(你可以通过退格键删除选择的值。
library(shiny)
ui <- fluidPage(
title = "Search Bar",
fluidRow(
selectizeInput(
inputId = "searchme",
label = "Search Bar",
multiple = FALSE,
choices = c("Search Bar" = "", paste0(LETTERS,sample(LETTERS, 26))),
options = list(
create = FALSE,
placeholder = "Search Me",
maxItems = '1',
onDropdownOpen = I("function($dropdown) {if (!this.lastQuery.length) {this.close(); this.settings.openOnFocus = false;}}"),
onType = I("function (str) {if (str === \"\") {this.close();}}")
)
))
)
server <- function(input, output, session) {
# Show Selected Value in Console
observe({
print(input$searchme)
})
}
shinyApp(ui, server)
搜索栏(多选)
在本节中,我们将展示如何从下拉菜单中选择一个以上的值。为了使多个部分工作,你需要设置multiple = TRUE ,以及在onItemAdd 选项中提到的JavaScript。
library(shiny)
ui <- fluidPage(
title = "Search Bar",
fluidRow(
selectizeInput(
inputId = "searchme",
label = "Search Bar",
multiple = TRUE,
choices = paste0(LETTERS,sample(LETTERS, 26)),
options = list(
create = FALSE,
placeholder = "Search Me",
onDropdownOpen = I("function($dropdown) {if (!this.lastQuery.length) {this.close(); this.settings.openOnFocus = false;}}"),
onType = I("function (str) {if (str === \"\") {this.close();}}"),
onItemAdd = I("function() {this.close();}")
)
))
)
server <- function(input, output, session) {
# Show Selected Value in Console
observe({
print(input$searchme)
})
}
shinyApp(ui, server)
在搜索栏中添加图标
如果你想添加搜索图标来改善搜索框的外观,你可以通过CSS样式来实现。我们使用的是Glyphicons图标,这是bootstrap自带的,所以你不需要为图标添加额外的库。
library(shiny)
ui <- fluidPage(
title = "Search Bar",
fluidRow(
tags$style(HTML("
.selectize-input.items.not-full.has-options:before {
content: '\\e003';
font-family: \"Glyphicons Halflings\";
line-height: 2;
display: block;
position: absolute;
top: 0;
left: 0;
padding: 0 4px;
font-weight:900;
}
.selectize-input.items.not-full.has-options {
padding-left: 24px;
}
.selectize-input.items.not-full.has-options.has-items {
padding-left: 0px;
}
.selectize-input.items.not-full.has-options .item:first-child {
margin-left: 20px;
}
")),
selectizeInput(
inputId = "searchme",
label = "Search Bar",
multiple = T,
choices = c("SBI Cap", "SBI Technology", "Kotak Technology"),
options = list(
create = FALSE,
placeholder = "Search Me",
onDropdownOpen = I("function($dropdown) {if (!this.lastQuery.length) {this.close(); this.settings.openOnFocus = false;}}"),
onType = I("function (str) {if (str === \"\") {this.close();}}"),
onItemAdd = I("function() {this.close();}")
)
))
)
server <- function(input, output, session) {
# Show Selected Value in Console
observe({
print(input$searchme)
})
}
shinyApp(ui, server)
在搜索栏中添加图片
要添加自定义图片,你可以将上一节的CSS改为下面的CSS。
.selectize-input.items.not-full.has-options:before {
content:'';
background: url('https://cdn.iconscout.com/icon/free/png-256/google-1772223-1507807.png'); /*url of image*/
height: 16px; /*height of image*/
width: 16px; /*width of image*/
position: absolute;
display: block;
position: absolute;
left: 0;
background-size: 16px 16px;
background-repeat: no-repeat;
margin-left: 3px;
}
.selectize-input.dropdown-active:before {
top: 0;
margin-top: 6px;
}
.selectize-input.items.not-full.has-options {
padding-left: 24px;
}
.selectize-input.items.not-full.has-options.has-items {
padding-left: 0px;
}
.selectize-input.items.not-full.has-options .item:first-child {
margin-left: 20px;
}
使用Shiny Widgets的搜索栏
shinyWidgets 是一个为shiny实现的小工具的伟大包。它提供了几个用于交互的控件。它有 widget的搜索栏,但它不允许在用户输入文本时提供建议。我们可以定制 widget,但它有一个限制,即不允许通过退格删除文本,但它在下拉菜单的顶部显示 按钮来清除选择。searchInput() pickerInput Clear Text
与上述selectizeInput 相比,这个实现有点混乱。它需要通过javascript和CSS进行修改。`live-search` = TRUE ,允许在下拉框中进行实时建议。
library(shiny)
library(shinyWidgets)
ui <- fluidPage(
title = "Search Bar",
fluidRow(
tags$script(HTML(
"var CONTROL_INTERVAL = setInterval(function(){
if($('#searchme').length > 0 ){
$('#searchme').on('show.bs.select', function(){
var input = $('.bootstrap-select:has(select[id=\"searchme\"]) .bs-searchbox > input');
var opts = $(this).parent().find('div[role=\"listbox\"] ul li');
var opts0 = $(this).parent().find('div[role=\"listbox\"]');
opts.hide();
opts0.hide();
input.on('input', function(e){
if ($(this).val() !== \"\") {opts.show(); opts0.show();}
else {opts.hide(); opts0.hide();}
});
});
clearInterval(CONTROL_INTERVAL);
}}, 200);
"
)),
tags$style(HTML(".bs-select-all {display: none;}
.bs-deselect-all {width: 100% !important;}")),
pickerInput(
inputId = "searchme",
label = "Search Bar",
choices = paste0(LETTERS,sample(LETTERS, 26)),
multiple = TRUE,
options = pickerOptions(title = "Search Me",
`live-search` = TRUE,
actionsBox = TRUE,
deselectAllText = "Clear Search")
)
))
server <- function(input, output, session) {
# Show Selected Value in Console
observe({
print(input$searchme)
})
}
shinyApp(ui, server)
带有大型选项列表的搜索栏
当你有大量的值时,选择会很慢。在下面的例子中,我们使用的是dqshiny 库,它非常有效。
library(shiny)
library(dqshiny)
# create 100K random words
opts <- sapply(1:100000, function(i) paste0(sample(letters, 7), collapse=""))
ui <- fluidPage(
fontawesome::fa_html_dependency(),
tags$style("input{font-family:'Font Awesome\ 5 Free';font-weight: 900;}
input:placeholder-shown#auto2{
background-image: url('https://cdn.iconscout.com/icon/free/png-256/google-1772223-1507807.png');
text-indent: 20px;
background-size: 16px 16px;
background-repeat: no-repeat;
background-position: 8px 8px;
}
input#auto2:focus{ background-image:none; text-indent: 0px;}"),
fluidRow(
column(3,
autocomplete_input("auto1", "Unnamed:", opts,
placeholder = " Search Value",
max_options = 1000),
autocomplete_input("auto2", "Named:",
placeholder = "Search Value",
max_options = 1000,
structure(opts, names = opts[order(opts)]))
), column(3,
tags$label("Value:"), verbatimTextOutput("val1", placeholder = TRUE),
tags$label("Value:"), verbatimTextOutput("val2", placeholder = TRUE)
)
)
)
server <- function(input, output) {
output$val1 <- renderText(as.character(input$auto1))
output$val2 <- renderText(as.character(input$auto2))
}
shinyApp(ui, server)