R Shiny:如何从数据表中的自定义按钮调用 JavaScript 函数
Posted
技术标签:
【中文标题】R Shiny:如何从数据表中的自定义按钮调用 JavaScript 函数【英文标题】:R Shiny: how to call a JavaScript function from a custom button inside a Datatable 【发布时间】:2021-02-10 07:19:58 【问题描述】:我已经下载并希望在我的 R Shiny 应用程序中加入以下 javascript 库:GitHub link
正如您在下面的 sn-p 中看到的,我已将 sequence-viewer.min.js
文件合并到 UI 的头部。另外,使用tags$div(id="sequence-viewer")
,我可以在网页的源代码中看到相应的<div>
标签,所以到目前为止我认为一切都很好。
使用以下代码,我构建并呈现了一个带有序列的示例数据表。从最后一列的链接,我想用Datatable的序列动态改变var seq=new Sequence('');
的值,并在每次点击链接时在sequence-viewer
div中绘制结果。
library(shiny)
ui <- fluidPage(
theme = shinytheme("yeti"),
useShinyjs(),
useShinyalert(),
tags$head(tags$script(src = "handlebars.js"),
tags$script(src = "sequence-viewer.min.js")),
mainPanel( DT::dataTableOutput("DTtable"),
br(),
tags$div(id="sequence-viewer")
)
)
server <- function(input, output)
exp1 <- reactive(
tbl <- as.data.frame(c("MALWMPGPGAGSL", "MALKYTFDCVBJUYGFGPGAGSL", "IUYTFVBNMKIUYF"))
names(tbl) <- "Sequence"
tbl$link <- createLink(tbl$Sequence)
return(tbl)
)
createLink <- function(val)
link <- paste0("<a href='#' onclick='var seq=new Sequence('",val,"'); seq.render('#sequence-viewer');'>Show seq</a>", sep="")
return(link)
output$DTtable <- DT::renderDataTable( exp1()
, escape = FALSE, options = list(scrollX = TRUE, dom = 'lfrtip', pageLength = 10,
lengthMenu=c(10, 25, 50, 100)), rownames = FALSE)
# Run the application
shinyApp(ui = ui, server = server)
我已经阅读了许多关于如何在 R Shiny 中运行自定义 javascript
代码的线程和教程,但是我发现的所有示例都在 ui
中调用,而不是在 server
端调用请您告诉我如何获得所需的输出?
注意: 根据 github 页面上的说明,需要依赖 jquery
、handlebars
和 bootstrap.min.css
。我想只有 handlebars.js
必须手动添加,因为 R Shiny 已经带有 bootstrap 和 jquery?
更新 1: 好的,我想我现在差不多了。感谢@YBS 的cmets,我设法了解了如何使用外部javascript 库。如果我单击actionLink
,下面的代码可以正常工作,但在单击我使用createLink
函数创建的数据表中的自定义链接时它不起作用。我在浏览器的控制台中收到以下异常:Uncaught ReferenceError: js$seque is not defined。任何想法为什么会发生这种情况?
library(shiny)
library(shinyjs)
jsCode = '
shinyjs.seque = function(params)
var defaultParams =
seq : "LKJHGFVBJKUGFKGFFGHJKUYTRFGHJUYTGHJIUYT"
;
params = shinyjs.getParams(params, defaultParams);
var seq=new Sequence(params.seq);
seq.render("#sequence-viewer");
'
ui <- fluidPage(
useShinyjs(),
extendShinyjs(text = jsCode, functions = c("seque")),
tags$head(tags$script(src = "handlebars.js"),
tags$script(src = "sequence-viewer.min.js")
),
mainPanel( DT::dataTableOutput("DTtable"),
br(),
actionLink(inputId = "action",
label = "action"),
br(),
tags$div(id="sequence-viewer")
)
)
server <- function(input, output)
exp1 <- reactive(
tbl <- as.data.frame(c("MALWMPGPGAGSL", "MALKYTFDCVBJUYGFGPGAGSL", "IUYTFVBNMKIUYF"))
names(tbl) <- "Sequence"
tbl$link <- createLink(tbl$Sequence)
return(tbl)
)
createLink <- function(val)
link <- paste0("<a href='#' onclick='js$seque(",val,")' id='",val,"' class='action-button shiny-bound-input'>Show sequence</a>", sep="")
return(link)
observeEvent(input$action,
js$seque("MALKYTFDCVBJUYGFGPGAGSL")
)
output$DTtable <- DT::renderDataTable(
exp1()
, escape = FALSE, options = list(scrollX = TRUE, dom = 'lfrtip', pageLength = 10,
lengthMenu=c(10, 25, 50, 100)), rownames = FALSE)
# Run the application
shinyApp(ui = ui, server = server)
更新 2:
经过数小时的调试,我设法通过将 createLink 函数中按钮的 onclick='js$seque(",val,")'
事件替换为以下内容来解决问题:onclick='shinyjs.seque(\"",val,"\")'
- 或者更清晰的 onclick='shinyjs.seque(JSON.stringify(val))'
简而言之,此时js$seque
调用不正确,我不得不将这一行替换为shinyjs.seque
,即用JS中函数的实际名称。另一方面,典型的 R actionButton
元素需要 js$seque
。我将尝试编写一个清晰的 MRE 代码并将其作为该线程的答案提供。
【问题讨论】:
能否分享任何相关链接,我可以阅读更多内容? 请看这里:***.com/questions/64159670/…,这里:***.com/questions/64277527/… 另外,请看deanattali.com/shinyjs 感谢您的链接。我认为前两个链接与我的问题不太相关,@DeanAttali 的第三个链接很有用,但所有提供的示例(甚至是高级示例)都是基于用户定义的 JS 函数,而不是外部 JS 库。跨度> @YBS 请看一下,我已经更新了我最初的问题 【参考方案1】:在您的情况下,shinyjs
的使用是一种过度杀伤力,因为您不想从 R 调用 JS 函数,而是通过客户端调用。因此,您可以像这个玩具示例一样简单地使用纯 JavaScript:
library(shiny)
js <- html("seque = function(seq)
alert(seq);
")
ui <- fluidPage(tags$head(tags$script(js)),
tags$a(hreg = "#", onclick = "seque('test message')",
"Click me to send test message"))
server <- function(...)
shinyApp(ui, server)
不要误会我的意思shinyjs
:有其优点,但典型的用例是您想从 R 端触发 JavaScript 代码,如下例所示:
library(shiny)
library(shinyjs)
js_code <- HTML("shinyjs.seque = function(par)
var def_par = seq: 'test message';
par = shinyjs.getParams(par, def_par);
alert(par.seq);
")
ui <- fluidPage(useShinyjs(),
extendShinyjs(text = js_code, functions = "seque"),
actionButton("click", "Click me to send message"))
server <- function(input, output, session)
observeEvent(input$click,
js$seque("test message from R")
)
shinyApp(ui, server)
在这个例子中,我使用shinyjs
直接从R调用JS,而在前面的例子中,JS是通过onclick
调用的。
对于您的示例,您可以在表中使用 actionLink
并添加一个观察者,在此您调用 js$queue
但由于每行都有一个链接,因此编码可能会很棘手(但并非不可能)(基本上你需要动态监听器),
因此,在您的示例中依赖纯 JS (onclick
) 可能是更好的选择,但是您不需要 shinyjs
。
【讨论】:
以上是关于R Shiny:如何从数据表中的自定义按钮调用 JavaScript 函数的主要内容,如果未能解决你的问题,请参考以下文章
如何在Shiny R中丢弃DT :: datatable上的用户编辑
在 R Shiny App 中,如何在首次调用 App 时呈现默认表格?
在 R Shiny 中,如何使用 actionButton 重置 rhandsontable 中的数据(反转所有手动输入)?