R Shiny - 动态创建书签 UI
R Shiny - bookmarking dynamically created UI
我在使用 Shiny 的书签时遇到了一个小问题(可能是错误?) - 我动态创建 UI - 新的文本和数字输入。这些输入是通过单击 ActionButton 创建的。保存书签时 URL - 数字和文本输入的值都在这个 URL 中。到目前为止,一切都很好。但是,在加载保存的 URL 后,我只看到第一个动态创建的 UI。我必须单击操作按钮才能添加下一个数字和文本输入。这些值保存在 URL 中,一旦添加了这些输入,它们就会填充正确的保存值。但是,如果您有 20 个这样的按钮,并且必须单击 19 次才能将它们全部显示在屏幕上,那就有点不方便了。
这是一个简短的可重现示例。
library(shiny)
ui <- function(request){
shinyUI(fluidPage(
bookmarkButton(),
sidebarLayout(
actionButton('addElement', 'Add Element', icon("plus"), class="btn-success text-white"),
mainPanel(
id ="content"
)
)
))
}
shinyServer(function(input, output) {
enableBookmarking("url")
countvar <<- 0
observeEvent(input$addElement, {
countvar <<- countvar + 1
element <- paste0("var", countvar)
insertUI(
selector = "#content",
where = "beforeEnd",
ui = tagList(
wellPanel(
style = "display:-webkit-inline-box;width:100%",
id = element,
column(3,
textInput(element, "Element name")
),
column(3,
numericInput(paste0(element, "Value"), "Element Value", NULL)
)
)
)
)
})
})
我在 SO 上发现了类似的问题,不幸的是没有答案 - Shiny app bookmarking: dynamic UI input lost
这是根据您的应用改编的最小示例。没有神奇的方法可以在添加书签后在页面上获取动态内容(除非您以直接的方式使用 renderUI——即没有任何非输入状态)。因此,对于您的情况,您只需在 onRestore()
回调中再次重复您在应用程序中所做的工作。执行此操作的最佳方法是重构您的代码,以便可以调用一个函数来在普通应用程序和 onRestore()
回调中添加项目。
library(shiny)
ui <- function(request) {
fluidPage(
bookmarkButton(),
sidebarLayout(
actionButton("add", "Add Element"),
mainPanel(id = "content")
)
)
}
server <- function(input, output, session) {
addItem <- function(id, textId, numberId, textVal = "", numberVal = NULL) {
insertUI(
selector = "#content",
where = "beforeEnd",
ui = tagList(
wellPanel(style = "display:-webkit-inline-box;width:100%",
id = id,
column(3, textInput(textId, "Element name", textVal)),
column(3, numericInput(numberId, "Element value", numberVal))
)
)
)
}
observeEvent(input$add, {
id <- paste0("var", input$add)
textId <- paste0(id, "text")
numberId <- paste0(id, "number")
addItem(id, textId, numberId)
}, ignoreInit = TRUE)
onRestore(function(state) {
for (i in seq_len(input$add)) {
id <- paste0("var", i)
textId <- paste0(id, "text")
numberId <- paste0(id, "number")
addItem(id, textId, numberId, input[[textId]], input[[numberId]])
}
})
}
enableBookmarking("url")
shinyApp(ui, server)
这是对 Barbara 的答案进行扩展的新答案。看来我们需要为 onRestore
函数引用状态变量才能正确处理用户的输入。所以我更改了她的代码以包含一个似乎有效的 state$input$var
。希望对你有帮助。
library(shiny)
ui <- function(request) {
fluidPage(
bookmarkButton(),
sidebarLayout(
actionButton("add", "Add Element"),
mainPanel(id = "content")
)
)
}
server <- function(input, output, session) {
addItem <- function(id, textId, numberId, textVal = "", numberVal = NULL) {
insertUI(
selector = "#content",
where = "beforeEnd",
ui = tagList(
wellPanel(style = "display:-webkit-inline-box;width:100%",
id = id,
column(3, textInput(textId, "Element name", textVal)),
column(3, numericInput(numberId, "Element value", numberVal))
)
)
)
}
observeEvent(input$add, {
id <- paste0("var", input$add)
textId <- paste0(id, "text")
numberId <- paste0(id, "number")
addItem(id, textId, numberId)
}, ignoreInit = TRUE)
onRestore(function(state) {
for (i in seq_len(input$add)) {
id <- paste0("var", i)
textId <- paste0(id, "text")
numberId <- paste0(id, "number")
addItem(id, textId, numberId, state$input[[textId]], state$input[[numberId]])
}
})
}
enableBookmarking("server")
shinyApp(ui, server)
我在使用 Shiny 的书签时遇到了一个小问题(可能是错误?) - 我动态创建 UI - 新的文本和数字输入。这些输入是通过单击 ActionButton 创建的。保存书签时 URL - 数字和文本输入的值都在这个 URL 中。到目前为止,一切都很好。但是,在加载保存的 URL 后,我只看到第一个动态创建的 UI。我必须单击操作按钮才能添加下一个数字和文本输入。这些值保存在 URL 中,一旦添加了这些输入,它们就会填充正确的保存值。但是,如果您有 20 个这样的按钮,并且必须单击 19 次才能将它们全部显示在屏幕上,那就有点不方便了。 这是一个简短的可重现示例。
library(shiny)
ui <- function(request){
shinyUI(fluidPage(
bookmarkButton(),
sidebarLayout(
actionButton('addElement', 'Add Element', icon("plus"), class="btn-success text-white"),
mainPanel(
id ="content"
)
)
))
}
shinyServer(function(input, output) {
enableBookmarking("url")
countvar <<- 0
observeEvent(input$addElement, {
countvar <<- countvar + 1
element <- paste0("var", countvar)
insertUI(
selector = "#content",
where = "beforeEnd",
ui = tagList(
wellPanel(
style = "display:-webkit-inline-box;width:100%",
id = element,
column(3,
textInput(element, "Element name")
),
column(3,
numericInput(paste0(element, "Value"), "Element Value", NULL)
)
)
)
)
})
})
我在 SO 上发现了类似的问题,不幸的是没有答案 - Shiny app bookmarking: dynamic UI input lost
这是根据您的应用改编的最小示例。没有神奇的方法可以在添加书签后在页面上获取动态内容(除非您以直接的方式使用 renderUI——即没有任何非输入状态)。因此,对于您的情况,您只需在 onRestore()
回调中再次重复您在应用程序中所做的工作。执行此操作的最佳方法是重构您的代码,以便可以调用一个函数来在普通应用程序和 onRestore()
回调中添加项目。
library(shiny)
ui <- function(request) {
fluidPage(
bookmarkButton(),
sidebarLayout(
actionButton("add", "Add Element"),
mainPanel(id = "content")
)
)
}
server <- function(input, output, session) {
addItem <- function(id, textId, numberId, textVal = "", numberVal = NULL) {
insertUI(
selector = "#content",
where = "beforeEnd",
ui = tagList(
wellPanel(style = "display:-webkit-inline-box;width:100%",
id = id,
column(3, textInput(textId, "Element name", textVal)),
column(3, numericInput(numberId, "Element value", numberVal))
)
)
)
}
observeEvent(input$add, {
id <- paste0("var", input$add)
textId <- paste0(id, "text")
numberId <- paste0(id, "number")
addItem(id, textId, numberId)
}, ignoreInit = TRUE)
onRestore(function(state) {
for (i in seq_len(input$add)) {
id <- paste0("var", i)
textId <- paste0(id, "text")
numberId <- paste0(id, "number")
addItem(id, textId, numberId, input[[textId]], input[[numberId]])
}
})
}
enableBookmarking("url")
shinyApp(ui, server)
这是对 Barbara 的答案进行扩展的新答案。看来我们需要为 onRestore
函数引用状态变量才能正确处理用户的输入。所以我更改了她的代码以包含一个似乎有效的 state$input$var
。希望对你有帮助。
library(shiny)
ui <- function(request) {
fluidPage(
bookmarkButton(),
sidebarLayout(
actionButton("add", "Add Element"),
mainPanel(id = "content")
)
)
}
server <- function(input, output, session) {
addItem <- function(id, textId, numberId, textVal = "", numberVal = NULL) {
insertUI(
selector = "#content",
where = "beforeEnd",
ui = tagList(
wellPanel(style = "display:-webkit-inline-box;width:100%",
id = id,
column(3, textInput(textId, "Element name", textVal)),
column(3, numericInput(numberId, "Element value", numberVal))
)
)
)
}
observeEvent(input$add, {
id <- paste0("var", input$add)
textId <- paste0(id, "text")
numberId <- paste0(id, "number")
addItem(id, textId, numberId)
}, ignoreInit = TRUE)
onRestore(function(state) {
for (i in seq_len(input$add)) {
id <- paste0("var", i)
textId <- paste0(id, "text")
numberId <- paste0(id, "number")
addItem(id, textId, numberId, state$input[[textId]], state$input[[numberId]])
}
})
}
enableBookmarking("server")
shinyApp(ui, server)