R语言 编辑 shiny.tag 元素



Background

我想更改shinydashboard::box的某些元素。比如说,我想更改用于折叠box(collapsible = TRUE)的图标。查看输出,我需要做的就是相应地更改<i>标签:

(b <- box(collapsible = T))
# <div class="col-sm-6">
#   <div class="box">
#    <div class="box-header">
#       <div class="box-tools pull-right">
#         <button class="btn btn-box-tool" data-widget="collapse">
#           <i class="fa fa-minus"></i> ## change to <i class="fa fa-times">
#         </button>
#       </div>
#    </div>
#    <div class="box-body"></div>
#   </div>
# </div>

挑战

虽然我可以在b$children中做一些递归循环来找到合适的子元素,例如

b$children[[1]]$children[[1]]$children[[2]]$children[[1]]$children[[1]]$attribs$class <- "fa fa-times"

我想知道,难道没有更简单的方法吗?理想情况下类似于jQuery语法?

另一种选择是编写我自己的box函数,但我想避免代码重复。

您可以编写一个帮助程序函数来编辑生成的 HTML。我们可以使用xml2中的函数来解析和编辑 html。例如

swap_node <- function(x, xpath, newval) {
parsed <- xml2::read_html(as.character(x))  
oldnode <- xml2::xml_find_all(parsed, xpath)
newnode <- xml2::read_html(as.character(newval))
xml2::xml_replace(oldnode, newnode)
shiny::HTML(as.character(xml2::xml_find_first(parsed, "//body/*")))
}

然后你可以像使用它一样

b <- shinydashboard::box(collapsible = T)
swap_node(b, "//i", shiny::tags$i(class="fa fa-times"))

但这在字符串而不是对象世界中运行。

这是一个函数,用于在搜索具有给定属性的给定类型的标签时导航shiny对象。如果找到,则会将其替换为具有新属性的新标记:

searchreplaceit <- function(branch, whattag, whatattribs, totag, toattribs) {
if ("name" %in% names(branch)) {
if ((branch$name == whattag)&&(identical( branch$attribs[names(whatattribs)], whatattribs))) {
branch$name    <- totag
branch$attribs <- modifyList(branch$attribs, toattribs)
}
}
if (class(branch)=="shiny.tag") {
if (length(branch$children)>0) for (i in 1: length(branch$children)) {
if (!(is.null(branch$children[[i]]))) {
branch$children[[i]] = searchreplaceit(branch$children[[i]], whattag, whatattribs, totag, toattribs)
} }
} else if (class(branch)=="list") {
if (length(branch)>0) for (i in 1:length(branch) ) {
if (!(is.null(branch[[i]]))) {
branch[[i]] <- searchreplaceit(branch[[i]], whattag, whatattribs, totag, toattribs)
} }
} 
return(branch)
}

例如,以下

b <- shinydashboard::box(collapsible = T)
searchreplaceit(b, "i", list(class="fa fa-minus"), "i", list(class="XXX"))

将在b内搜索具有(至少)属性class="fa fa-minus""i"标签。找到后,它将替换为标记"i"和属性class="XXX"

# <div class="col-sm-6">
#   <div class="box">
#     <div class="box-header">
#       <div class="box-tools pull-right">
#         <button class="btn btn-box-tool" data-widget="collapse">
#           <i class="XXX" role="presentation" aria-label="minus icon"></i>
#         </button>
#       </div>
#     </div>
#     <div class="box-body"></div>
#   </div>
# </div>

搜索一直持续到扫描完整个对象。

唯一的困难是(1)由shinyObjects产生的对象交错shiny.tag子对象和list子对象;(2) 某些元素有时为 NULL。

该函数是一个递归函数;对于访问的任何分支(类shiny.tag的对象)或子列表,它返回修改后的元素。

最新更新