我有一个复杂的闪亮的应用程序,需要使用自定义JavaScript代码。该应用程序由不同名称空间的多个地方调用的模块组成。我需要一些JavaScript代码与R代码一起“模块化”,即使用模块名称空间。我能够通过创建一个包含JS代码的定制字符串并使用shinyjs::runjs()函数执行它(下面的示例)来使它工作。例如,这是一个公平的解决方案。但是,将更复杂的超过100行的JavaScript代码放入一个使用标识符粘贴的字符串中,似乎非常容易出错,而且解决方案也不太理想(缺少高亮显示、格式痛苦等等)。是否有更好的方法来达到同样的效果?
library(shiny)
library(shinyJS)
myModuleUI <- function(id) {
ns <- NS(id)
tagList(
div(id = ns("clickableElement"), class = "btn btn-primary", "Click Me"),
div(id = ns("highlightableElement"), "This (and only this!) text should be highlighted on click")
)
}
myModule <- function(input, output, session) {
ns <- session$ns
shinyjs::runjs(paste0("
$('#", ns("clickableElement"), "').click(function() {
$('#", ns("highlightableElement"), "').css('background', 'yellow');
})
"))
}
ui <- fluidPage(
useShinyjs(),
tabsetPanel(
tabPanel(
"Instance 1",
myModuleUI("one")
),
tabPanel(
"Instance 2",
myModuleUI("two")
)
)
)
server <- function(input, output) {
callModule(myModule, "one")
callModule(myModule, "two")
}
shinyApp(ui = ui, server = server)更新
作为将来的参考,我决定分享我最终实现的解决方案。最后,我创建了每个模块一个JS文件,其中包含一个函数,将名称空间作为惟一的参数。此函数使用此命名空间创建所有需要的对象和绑定。然后,在模块开始时使用shinyjs调用该单个函数。这允许我将JS代码保存在一个单独的文件中,该文件解决了初始问题,并使代码易于管理(特别是如果您有大量JS代码)。
app.R
library(shiny)
library(shinyjs)
myModuleUI <- function(id) {
ns <- NS(id)
tagList(
div(id = ns("clickableElement"), class = "btn btn-primary", "Click Me"),
div(id = ns("highlightableElement"), "This (and only this!) text should be highlighted on click")
)
}
myModule <- function(input, output, session) {
ns <- session$ns
shinyjs::runjs(paste0("myModuleJS('", ns(""), "');"))
}
ui <- fluidPage(
useShinyjs(),
tags$head(
tags$script(src = "myModuleJS.js")
),
tabsetPanel(
tabPanel(
"Instance 1",
myModuleUI("one")
),
tabPanel(
"Instance 2",
myModuleUI("two")
)
)
)
server <- function(input, output) {
callModule(myModule, "one")
callModule(myModule, "two")
}
shinyApp(ui = ui, server = server)www/myModuleJS.js
function myModuleJS(ns) {
$('#' + ns + 'clickableElement').click(function() {
$('#' + ns + 'highlightableElement').css('background', 'yellow');
});
}发布于 2018-02-22 16:07:01
我认为有两种方法可以解决这一问题,尽管它们不是非常优雅的解决方案。
第一个解决方案是定义几个全局函数,例如getJavascriptSelector <- function(id, session){paste0("'#", session$ns(id), "'")}。这样,每次使用选择器时仍然需要调用此函数,并且不能在单独的文件中定义js。
因为您正在运行的javascript都是字符串,另一个解决方案是您可以定义一个函数,比如wrapJavascriptWithNamespace(script, ns),它接受脚本字符串(或js文件)和ns对象。该函数将使用regexp匹配并用会话命名空间选择器替换选择器。这样,您也可以重用您的javascript代码,但需要更多的工作,并且可能存在一些问题,例如,如果该代码需要引用全局范围元素(这可以通过使用一些关键字标记javascript使其成为模板来解决)。如果将示例中使用的代码放在字符串中:
$('#[shiny-namespace]clickableElement').click(function() {
$('#[shiny-namespace]highlightableElement').css('background', 'yellow');
}) 您可以轻松地解析这个字符串并用ns()替换shiny-namespace。当您需要这个字符串成为普通的javascrip模板时,您只需要编写另一个函数就可以去掉[shiny-namespace]标记。
https://stackoverflow.com/questions/48929528
复制相似问题