我正在尝试在渲染输出后在 Shiny 中执行操作。由于我尝试滚动到输出的位置,因此输出存在于我尝试这样做之前是至关重要的。如何检查输出对象是否存在(它是用 renderUI
创建的),或者服务器输出渲染是否完成?我还没有在网上或其他网站上找到任何与此相关的信息。
MWE:愚蠢的布局是为了帮助展示我想要的东西。这个想法是在单击按钮时生成一些输出,然后 then、after 生成输出,滚动到该输出的底部。尽管使用了 priority
字段,但它永远不会在第一代输出上起作用。
ui <- function(id){
fluidPage(
tags$head(
tags$script(
"Shiny.addCustomMessageHandler('scroll_to_item', function(button) {
document.getElementById(button).scrollIntoView({
alignToTop: false,
behavior: 'smooth'
});
});"
)
),
fluidRow(
column(2,
fluidRow(
div(HTML(stringi::stri_rand_lipsum(10))),
actionButton("create_plot", label = "Create plot", icon = icon("picture", library = "glyphicon"))
),
),
column(10)
),
uiOutput("show_output")
)
}
server <- function(input, output, session){
show_aggregations <- eventReactive(input$create_plot, ignoreInit = TRUE, label = "Output to be displayed", {
message(whereami::whereami())
return(fluidRow(HTML(stringi::stri_rand_lipsum(1))))
})
output$show_output <- renderUI({
message(whereami::whereami())
return(show_aggregations())
})
outputOptions(output, "show_output", priority = 100)
observeEvent(show_aggregations(), label = "Scroll once the output has rendered", {
message(whereami::whereami())
session$sendCustomMessage("scroll_to_item", "show_output")
}, priority = 1)
}
shinyApp(ui, server)
Shiny.addCustomMessageHandler
和
session$sendCustomMessage
)以及 session$onFlushed
解决了这个问题。后者用于收集 JavaScript 中感兴趣的输出值(在我的例子中,我对输出的 HTML 代码中的任何更改感兴趣)afterShiny 刷新了反应式系统,这是正确的时机案例:
session$onFlushed(function() session$sendCustomMessage("flush_message", ""), once = FALSE) # R Shiny server
Shiny.addCustomMessageHandler('flush_message', function(value) {
Shiny.setInputValue('flush', $('#show_output')[0].innerHTML);
}); // JS script
Shiny.setInputValue
在 Shiny 会话中将输出内容作为
input$flush
发回。观察者使 input$flush
上的任何更改无效,然后触发滚动事件observeEvent(input$flush, ignoreNULL = TRUE, label = "Scroll once the output has rendered", {
message(whereami::whereami())
if(rv_local$scroll) session$sendCustomMessage("scroll_to_item", "show_output")
rv_local$scroll <- FALSE
})
rv_local$scroll
是一个无功值,当输出更新时,它用作开关,设置为
TRUE
;一旦执行滚动,则设置为 FALSE
;它确保滚动仅在我想要的时候执行,而不是在每次刷新之后执行。闪亮的应用程序
ui <- function(id){
fluidPage(
includeScript(path = "www/myscript.js"), # The JS script HAS to be stored in a directory named www
fluidRow(
column(2,
fluidRow(
div(HTML(stringi::stri_rand_lipsum(10))),
actionButton("create_plot", label = "Create plot", icon = icon("picture", library = "glyphicon"))
),
),
column(10)
),
uiOutput("show_output")
)
}
server <- function(input, output, session){
rv_local <- reactiveValues(scroll = FALSE)
show_aggregations <- eventReactive(input$create_plot, ignoreInit = TRUE, ignoreNULL = TRUE, label = "Output to be displayed", {
message(whereami::whereami())
return(fluidRow(HTML(stringi::stri_rand_lipsum(1))))
})
output$show_output <- renderUI({
message(whereami::whereami())
req(show_aggregations())
rv_local$scroll <- TRUE
return(show_aggregations())
})
observeEvent(input$flush, ignoreNULL = TRUE, label = "Scroll once the output has rendered", {
message(whereami::whereami())
if(rv_local$scroll) session$sendCustomMessage("scroll_to_item", "show_output")
rv_local$scroll <- FALSE
})
session$onFlushed(function() session$sendCustomMessage("flush_message", ""), once = FALSE)
}
shinyApp(ui, server)
JS脚本
Shiny.addCustomMessageHandler('scroll_to_item', function(button) {
document.getElementById(button).scrollIntoView({
alignToTop: false,
behavior: 'smooth'
});
});
Shiny.addCustomMessageHandler('flush_message', function(value) {
Shiny.setInputValue('flush', $('#show_output')[0].innerHTML);
});