我正在尝试使用JohnCoene/marker包来突出显示闪亮应用程序中的文本部分。我的意图是首先使用某些服务器逻辑生成文本并使用textOutput
显示它。但是,我正在努力尝试在文本出现在网站上之后如何触发 marker
。将其放在相同的observeEvent()
中是行不通的。
这是我的代表
# remotes::install_github("johncoene/marker")
library(shiny)
library(marker)
ui <- fluidPage(
use_marker(),
actionButton("click", "click"),
textOutput("text_to_mark")
)
server <- function(input, output) {
observeEvent(input$click,
{
output$text <- renderText("My house is yellow")
})
# observeEvent() below does not work. This is just for illustration
observeEvent(input$text_to_mark,
{
marker <- marker$new("#text_to_mark.shiny-text-output.shiny-bound-output")
marker$
unmark()$ # unmark all before we mark
mark("My house")
})
}
# Run the application
shinyApp(ui = ui, server = server)
由reprex package(v0.3.0)于2019-10-10创建
为便于说明:我可以通过添加下面的代码中的第二个按钮来使标记起作用,但是我正在寻找一种解决方案,当文本出现时触发它。
# remotes::install_github("johncoene/marker")
library(shiny)
library(marker)
ui <- fluidPage(
use_marker(),
actionButton("click", "click"),
textOutput("text_to_mark"),
actionButton("mark", "Mark!")
)
server <- function(input, output) {
observeEvent(input$click,
{
output$text_to_mark <- renderText("My house is yellow")
})
observeEvent(input$mark,
{
marker <- marker$new("#text_to_mark.shiny-text-output.shiny-bound-output")
marker$
unmark()$ # unmark all before we mark
mark("My house")
})
}
# Run the application
shinyApp(ui = ui, server = server)
由reprex package(v0.3.0)于2019-10-10创建
答案 0 :(得分:1)
您可以使用JavaScript Is there a JavaScript / jQuery DOM change listener?监听DOM的更改。
发生更改时,您可以检查目标元素是否包含文本:
hasText = document.getElementById("text_to_mark").innerHTML != ""
请注意,我假设您的元素的ID为“ text_to_mark”。
您可以使用
“发送到R”的结果 Shiny.onInputChange("hasText", hasText);
在R端,您可以通过侦听input$hasText
来知道元素是否具有文本。
因此您可以添加:
observeEvent(input$hasText,{
...
})
您可以使用tags$script(jsCode)
或使用shinyjs
将JavaScript添加到您的应用中。
可复制的示例:
library(shiny)
library(marker)
jsCode <- '
MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
var observer = new MutationObserver(function(mutations, observer) {
console.log(mutations, observer);
hasText = document.getElementById("text_to_mark").innerHTML != ""
Shiny.onInputChange("hasText", hasText);
});
observer.observe(document, {
subtree: true,
attributes: true
});
'
ui <- fluidPage(
use_marker(),
tags$script(jsCode),
actionButton("click", "click"),
textOutput("text_to_mark"),
actionButton("mark", "Mark!")
)
server <- function(input, output) {
observeEvent(input$click, {
output$text_to_mark <- renderText("My house is yellow")
})
observeEvent(input$hasText,{
marker <- marker$new("#text_to_mark.shiny-text-output.shiny-bound-output")
marker$
unmark()$ # unmark all before we mark
mark("My house")
})
}
# Run the application
shinyApp(ui = ui, server = server)
请注意,这仅适用于文本的首次出现。如果您还想听文本的更改,可以将文本发送给R,然后在R侧检查文本是否已更新。不知道这里是否需要。
答案 1 :(得分:1)
侦听DOM更改是一种选择,但是您的方法已经显示出有一种纯粹的闪亮(非自定义JS)解决方案,只需多单击一次,因此问题是如何仅需单击一下即可实现。我建议使用invalidateLater
并将其包装在if
语句中,以防止它像看到的here那样一遍又一遍地运行。
技巧是在observe
语句中运行标记调用。在此处包括invalidateLater
并将其包装在if
条件下,并带有一个计数器,该计数器对执行该语句的次数进行计数。用毫秒数和计数来计算,在我的情况下,它可以与if(isolate(val$cnt) < 1)
和invalidateLater(1000)
一起正常工作。不要忘记将计数器包装在isolate
中,否则它将陷入循环中。
还请注意,input$click
不仅将文本写入reactValue,还将计数器val$cnt
重置为0
,以便您可以在新的invalidateLater
上再次使用文本。如果您想使用observeEvent之类的内容来更新文本,相同的过程将为您提供帮助。只需确保将计数器重置为0,高亮显示在新文本部分即可。
# remotes::install_github("johncoene/marker")
library(shiny)
library(marker)
ui <- fluidPage(
use_marker(),
actionButton("click", "click"),
textOutput("text_to_mark")
)
server <- function(input, output) {
val <- reactiveValues(cnt = 0,
text = NULL)
observeEvent(input$click, {
val$text <- "My house is yellow"
val$cnt <- 0
})
observe({
if(isolate(val$cnt) < 1) {
invalidateLater(1000)
}
marker <- marker$new("#text_to_mark.shiny-text-output.shiny-bound-output")
marker$
unmark()$ # unmark all before we mark
mark("My house")
val$cnt = isolate(val$cnt) + 1
})
output$text_to_mark <-renderText({
val$text
})
}
# Run the application
shinyApp(ui = ui, server = server)