【问题标题】:R Shiny - bookmarking dynamically created UIR Shiny - 为动态创建的 UI 添加书签
【发布时间】:2017-11-30 12:57:57
【问题描述】:

我在 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

【问题讨论】:

  • 您需要使用onRestore()函数。看看这篇文章:shiny.rstudio.com/articles/advanced-bookmarking.html
  • 嗨,芭芭拉,感谢您的链接。我想我知道问题出在哪里——即使在 URL 中 addElement 的值大于 1,它也只会触发一次。但是我不确定如何将onRestore() 函数合并到我的代码中。我到底应该调用什么 - 触发代码的“observeElement”部分?还是简单地解析纯 HTML?谢谢,我现在有点迷路了。

标签: r shiny bookmarks shinyjs


【解决方案1】:

这是一个改编自您的应用的最小示例。书签后没有神奇的方法可以在页面上获取动态内容(除非您以直接的方式使用 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)

【讨论】:

  • 我担心会是这样——我有很多动态生成的内容,所以总体上会有点乱。非常感谢您的宝贵时间,感谢您的意见!
  • 我还意识到我可以在 observeEvent handlerExpr 中使用一个函数。因此,我创建了一个函数,我在 observeEvent 和 onRestore 阶段都将其称为 ib。到目前为止,它工作得很好。
  • @ledogbert 想知道您是否可以发布用于创建要由 observeEvent 和 onRestore 处理的函数的代码。我正在尝试做类似的事情,但恢复失败,没有任何有用的错误消息......
【解决方案2】:

这是扩展芭芭拉的答案的新答案。看来我们需要引用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) 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-04-09
    • 2020-10-14
    • 1970-01-01
    • 2014-07-04
    • 2020-03-04
    • 2016-12-03
    • 2017-01-09
    • 1970-01-01
    相关资源
    最近更新 更多