R Shiny - 为动态创建的UI添加书签

问题描述 投票:0回答:2

我发现了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

r shiny bookmarks shinyjs
2个回答
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)

0
投票

这是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) 
© www.soinside.com 2019 - 2024. All rights reserved.