我有一个带有多个选项卡的 Shiny 应用程序,我在其中渲染rhandsontable并希望提供搜索功能。这是我编写的用于使用搜索呈现此类表格的模块:
# Module for rendering rhandsontable with search
rtable_UI <- function(id) {
ns <- NS(id)
tagList(
textInput("searchField", "Search"),
rhandsontable::rHandsontableOutput(ns('table_output'))
)
}
rtableServer <- function(id, df) {
moduleServer(id, function(input, output, session) {
output$table_output <- rhandsontable::renderRHandsontable({
rhandsontable::rhandsontable(df, search = TRUE)
})
})
}
请注意,searchField 不在其命名空间中。如果我尝试 ns("searchField")
搜索功能在我 Shiny 的应用程序中不起作用:
# Shiny App
ui <- navbarPage(
"example",
tabPanel(
'First Tab',
rtable_UI('table1')
),
tabPanel(
'Second Tab',
rtable_UI('table2')
)
)
server <- function(input, output, session){
rtableServer('table1', iris)
rtableServer('table2', mtcars)
}
shinyApp(ui, server)
搜索功能仅适用于第一个选项卡,我认为这是因为搜索字段的 id 是相同的。然而,更改 id 似乎也不是一个选项,如 here 所示。 。有没有办法让rhandsontable知道命名空间?
最佳答案
这是一个相当痛苦的练习! RHandsontable 真的很想负责搜索……我离题了。
如果您添加了更多表,您唯一需要添加的是我编写的位置 tbr[1].classList.add('active');/* 因此数据可用 */
.加载时仅加载第一个选项卡。您需要加载所有选项卡才能使代码正常工作。这只需发生一次,因此,例如,如果有三个表,则需要添加 tbr[2].classList.add('active');
。
I didn't use any string safeguards (setting it to lowercase, trimming whitespace, etc.).
我在这里将搜索输入框的 id 更改为 searcher
,这样 rhandsontable
包就无法识别它。这必须与 JS 中使用的 id 相匹配,因此如果您在此处更改此字符串,它也必须在那里更改。
rtable_UI <- function(id) {
ns <- NS(id)
tagList(
textInput(ns("searcher"), "Search"),
rhandsontable::rHandsontableOutput(ns('table_output'))
)
}
这没有改变。
rtableServer <- function(id, df) {
moduleServer(id, function(input, output, session) {
output$table_output <- rhandsontable::renderRHandsontable({
rhandsontable::rhandsontable(df, search = T)
})
})
}
对于 ui
,我添加了 tagList
、tags$head
、一个样式标签和两个脚本。一个脚本是 Shiny 渲染所需的更改;另一个脚本是搜索功能。这里编码的一些内容肯定可以使用 shiny
和 htmltools
之间的 tag
函数来完成,但这对我来说更容易一些。
ui <- tagList(
tags$head(
tags$style(HTML(
".htSearchResult {background-color: rgb(252, 237, 217);}")),
tags$script(type="text/javascript", HTML("setTimeout(function(){
var tbr = document.querySelectorAll('.tab-pane');
tbr[1].classList.add('active'); /* so the data is avail */
var inStr = document.querySelectorAll('input'); /*the input boxes*/
var widg = document.querySelectorAll('.html-widget'); /*the tables boxes*/
for(i = 0; i < widg.length; i++) {
var wId = widg[i].getAttribute('id'); /* collect table IDs */
inStr[i].className = ''; /* disassociate rhandstable search */
inStr[i].style.cssText = 'cursor: pointer; font-size: 1em; line-height: 1.5em; padding: 6px 12px; display: block; width: 70%;';
/* collect label and input box; add event without rhandsontable interference */
var par = inStr[i].parentElement
var ipar = par.children[0].outerHTML;
var str = inStr[i].outerHTML;
var html = '\"replacer(\\'' + wId + '\\')\"';
str = str.replace('>', ' onkeyup=' + html + '>');
par.innerHTML = ipar + str;
}
}, 100)")),
tags$script(type="text/javascript", HTML("function replacer(tbl) {
$('#' + tbl).first().find('.htSearchResult').removeClass('htSearchResult'); /*remove previous search highlight*/
var searchword = $('#' + tbl.substring(0,6) + '-searcher').val(); /* collect input */
var custfilter = new RegExp(searchword, 'ig'); /* setup input for search */
if (searchword !== '') {
looker = document.querySelector('#' + tbl);
tellMe = looker.querySelectorAll('td'); /*look at all table cells of specific table*/
for(i = 0; i < tellMe.length; i++) {
tm = tellMe[i].innerText.toString();
if(tm.includes(searchword)){
console.log(tellMe[i]);
tellMe[i].classList.add('htSearchResult'); /*highlight partial match table cells*/
}
}
}
}"))),
navbarPage(
"example",
tabPanel(
'First Tab',
rtable_UI('table1')
),
tabPanel(
'Second Tab',
rtable_UI('table2')
)
))
对服务器
的调用未更改。
server <- function(input, output, session){
rtableServer('table1', iris)
rtableServer('table2', mtcars)
}
shinyApp(ui, server)
更新了滚动
好的 - 此更新是关于滚动并确保文本突出显示。
我知道由于多种原因,您现在正在处理的内容并不反射(reflect)此答案中的内容。首先,我将用文字概述我所做的事情,然后编写代码(基于我原来的答案)。
我基本上拆分了函数replacer
。对于滚动,您不想删除突出显示。因此,有一个包含所有代码的函数(称为 addMore
),它包含除 replacer
第一行之外的所有内容。 replacer
函数只有原始的第一行,然后调用函数 addMore
。
当您添加函数来创建搜索栏时,表格不可用。因此,没有任何东西可以附加 onscroll
事件。因此,我创建了一个 keydown
事件,以便第一次搜索表格时,它会从 input
框中删除 keydown
事件并添加一个scroll
事件到右侧元素(小部件的第一个子元素的第一个子元素)。您可能想要使用与 keydown
不同的事件,因为您首先键入的内容都不在输入框中。 (这可能很烦人!)
首先是addMore
函数
tags$script(type="text/javascript", HTML("
function addMore(tbl) {
var searchword = $('#' + tbl.substring(0,6) + '-searcher').val(); /* collect input */
var custfilter = new RegExp(searchword, 'ig'); /* setup input for search */
if (searchword !== '') {
looker = document.querySelector('#' + tbl);
tellMe = looker.querySelectorAll('td'); /*look at all table cells of specific table*/
for(i = 0; i < tellMe.length; i++) {
tm = tellMe[i].innerText.toString();
if(tm.includes(searchword)){
console.log(tellMe[i]);
tellMe[i].classList.add('htSearchResult'); /*highlight partial match table cells*/
}
}
}
}"))
新的replacer
函数。
tags$script(type="text/javascript", HTML("function replacer(tbl) {
$('#' + tbl).first().find('.htSearchResult').removeClass('htSearchResult'); /*remove previous search highlight*/
addMore(tbl);
}"))
此函数用于删除 keydown
事件并添加 onscroll
事件。
tags$script(type="text/javascript", HTML("function popOnce(inid, widd){
win = document.querySelector('input#' + inid);
/*wait for the first attempt to search to add listeners for scroll*/
var par = win.parentElement
var ipar = par.children[0].outerHTML;
var str = win.outerHTML;
rx = /onkeydown.*\"/g;
str = str.replace(rx, '');
par.innerHTML = ipar + str;
widg = document.querySelector('div#' + widd);
where = widg.querySelector('div.ht_master > div.wtHolder');
where.addEventListener('scroll', function(){addMore(widd)});
}")),
最后是setTimeout
函数。在此函数中,我在添加 onkeyup
的同时添加了 onkeydown
。
tags$script(type="text/javascript", HTML("setTimeout(function(){
var tbr = document.querySelectorAll('.tab-pane');
tbr[1].classList.add('active'); /* so the data is avail */
var inStr = document.querySelectorAll('input[id*=\"searcher\"]'); /*the input boxes*/
console.log(inStr[0].getAttribute('id'));
var widg = document.querySelectorAll('.html-widget'); /*the tables boxes*/
for(i = 0; i < widg.length; i++) {
var wId = widg[i].getAttribute('id'); /* collect table IDs */
var insid = inStr[i].getAttribute('id');
inStr[i].className = ''; /* disassociate rhandstable searcher */
inStr[i].style.cssText = 'cursor: pointer; font-size: 1em; line-height: 1.5em; padding: 6px 12px; display: block; width: 70%;';
/* collect label and input box; add event without rhandsontable interference */
var par = inStr[i].parentElement
var ipar = par.children[0].outerHTML;
var str = inStr[i].outerHTML;
var html = '\"replacer(\\'' + wId + '\\')\"';
var html2 = '\"popOnce(\\'' + insid + '\\',\\'' + wId + '\\')\"';
/*str = str.replace('>', ' onkeyup=' + html + '>'); original before highlight scrolling */
str = str.replace('>', ' onkeyup=' + html + ' onkeydown=' + html2 + '>');
par.innerHTML = ipar + str;
}}, 400)"))
这与上面的代码相同,但它们都作为一个代码块组合在一起。
rtable_UI <- function(id) {
ns <- NS(id)
tagList(
textInput(ns("searcher"), "Search"),
rhandsontable::rHandsontableOutput(ns('table_output'))
)
}
rtableServer <- function(id, df) {
moduleServer(id, function(input, output, session) {
output$table_output <- rhandsontable::renderRHandsontable({
rhandsontable::rhandsontable(df, search = T, height = 700)
})
})
}
# Shiny App
ui <- tagList(
tags$head(
tags$style(HTML("
.htSearchResult {
background-color: rgb(252, 237, 217);
}
.rhandsontable.html-widget {
overflow: hidden;
}")),
# next function was replacer—without the removing the highlighting
tags$script(type="text/javascript", HTML("
function addMore(tbl) { /* collect input */
var searchword = $('#' + tbl.substring(0,6) + '-searcher').val();
var custfilter = new RegExp(searchword, 'ig'); /* setup input for search */
if (searchword !== '') {
looker = document.querySelector('#' + tbl);
tellMe = looker.querySelectorAll('td'); /*look at all table cells of specific table*/
for(i = 0; i < tellMe.length; i++) {
tm = tellMe[i].innerText.toString();
if(tm.includes(searchword)){
console.log(tellMe[i]);
tellMe[i].classList.add('htSearchResult'); /*highlight partial match table cells*/
}
}
}
}")),
tags$script(type="text/javascript", HTML("function popOnce(inid, widd){
win = document.querySelector('input#' + inid);
/*wait for the first attempt to search to add listeners for scroll*/
var par = win.parentElement
var ipar = par.children[0].outerHTML;
var str = win.outerHTML;
rx = /onkeydown.*\"/g;
str = str.replace(rx, '');
par.innerHTML = ipar + str;
widg = document.querySelector('div#' + widd);
where = widg.querySelector('div.ht_master > div.wtHolder');
where.addEventListener('scroll', function(){addMore(widd)});
}")),
tags$script(type="text/javascript", HTML("setTimeout(function(){
var tbr = document.querySelectorAll('.tab-pane');
tbr[1].classList.add('active'); /* so the data is avail */
var inStr = document.querySelectorAll('input[id*=\"searcher\"]'); /*the input boxes*/
console.log(inStr[0].getAttribute('id'));
var widg = document.querySelectorAll('.html-widget'); /*the tables boxes*/
for(i = 0; i < widg.length; i++) {
var wId = widg[i].getAttribute('id'); /* collect table IDs */
var insid = inStr[i].getAttribute('id');
inStr[i].className = ''; /* disassociate rhandstable searcher */
inStr[i].style.cssText = 'cursor: pointer; font-size: 1em; line-height: 1.5em; padding: 6px 12px; display: block; width: 70%;';
/* collect label and input box; add event without rhandsontable interference */
var par = inStr[i].parentElement
var ipar = par.children[0].outerHTML;
var str = inStr[i].outerHTML;
var html = '\"replacer(\\'' + wId + '\\')\"';
var html2 = '\"popOnce(\\'' + insid + '\\',\\'' + wId + '\\')\"';
/* highlight scrolling modification */
str = str.replace('>', ' onkeyup=' + html + ' onkeydown=' + html2 + '>');
par.innerHTML = ipar + str;
}}, 400)")),
tags$script(type="text/javascript", HTML("function replacer(tbl) {
$('#' + tbl).first().find('.htSearchResult').removeClass('htSearchResult'); /*remove previous search highlight*/
addMore(tbl);
}"))),
navbarPage(
"example",
tabPanel(
'First Tab',
rtable_UI('table1')
),
tabPanel(
'Second Tab',
rtable_UI('table2')
)
))
server <- function(input, output, session){
rtableServer('table1', iris)
rtableServer('table2', mtcars)
}
shinyApp(ui, server)
关于r - 在 Shiny 的应用程序中搜索多个 rhandsontable 的功能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69969852/