首页 文章

如何使用动态选项为Shiny selectizeInput添加书签?

提问于
浏览
0

Shiny提供 selectizeInput 包装 selectize.js ,它生成一个文本输入/组合框小部件 . 我有几个原因希望用户能够创建新值(例如,选择现有值或创建自己的值) .

但在所有这些情况下,selectizeInput的值无法使用Shiny的服务器端书签进行书签 . 初始化selectizeInput对象时,存储在 input 中的书签值尚不是有效的选项值 .

有没有人有任何聪明的解决方法来为selectizeInput值添加书签?

这是处理 create 选项的最简单示例:

library(shiny)

ui <- function(request) {
  fluidPage(

    selectizeInput("foo", "Created Values Cannot Be Bookmarked", choices=c("Choose From List or Type New Value"="", "bar", "baz"),
                   options=list(create=TRUE)),
    bookmarkButton("Update URL")

  )}

server <- function(input, output) {
  onBookmarked(function(url) {
    updateQueryString(url)
  })
}

shinyApp(ui = ui, server = server, enableBookmarking = "server")

如果在选择框中键入新值,请单击书签按钮以更新浏览器中位置栏中的URL,然后单击重新加载,则该创建的值将丢失 . 对现有选项尝试相同,当然也可以 .

如果选项加载延迟会变得更复杂,但问题是相同的,即 selectizeInput 渲染时用户的选择无效 .

2 回答

  • 0

    这是一个解决方法hack,扩展了原始问题的示例 . 在这个例子中,我也显示延迟加载 .

    selectizeInput 的重复值存储在隐藏文本输入中 . 加载书签值后,隐藏备份值将用于恢复真实值 . 要设置不在当前选项中的值,请使用shinyjs将 selectize.js API调用为 addOption ,然后调用 addItem . 请注意输入$ foo观察者上的 ignoreInit=TRUE ,以便在加载时不会覆盖隐藏的备份 . 另一方面,在输入$ foo.bak观察者上设置 once=TRUE ,以便隐藏备份仅用于在启动时更新实际值 . 请参阅 observeEvent 的文档 .

    仅当焦点在输入上以加速初始页面加载时,才会异步加载 selectizeInput 的选项 . 带有选项的JSON文件存储在本地www /目录中 .

    此示例还允许多个选择 . 选定的项目以逗号分隔的方式存储在隐藏文本字段中,然后在初始化期间进行扩展 .

    library(shiny)
    library(shinyjs)
    
    # create JSON file with selectizeInput choices to be retrieved via ajax during load
    # normally this would be run once outside of app.R
    dir.create("www")
    foo.choices.json <- paste('{ "cars": [\n', paste0('{ "value": "', rownames(mtcars), '", "label": "',rownames(mtcars), '" }', collapse=",\n" ), "\n]}")
    writeChar(foo.choices.json, "www/foo.choices.json", eos=NULL)
    
    # javascript to set one or more values
    jsCode <- "shinyjs.setfoo = function(params){ 
      x=$('#foo')[0].selectize; 
      $.each(params.items, function(i,v) { x.addOption({value:v,label:v}); x.addItem(v) })
    }"
    
    # javascript to retrieve the choices asynchronously after focus
    foo.load <- "function(query, callback) {
      if (query.length) return callback(); // not dynamic by query, just delayed load
      $.ajax({
        url: 'foo.choices.json',
        type: 'GET',
        error: function() { callback() },
        success: function(res) { callback(res.cars) }
      })
    }"
    
    ui <- function(request) {
      fluidPage(
        useShinyjs(), 
        extendShinyjs(text=jsCode),
        titlePanel("Bookmarking Created Values"),
        selectizeInput("foo", NULL, 
                       choices=c("Choose From List or Type New Value"=""),
                       multiple=TRUE,
                       options=list(create=TRUE, preload="focus", load=I(foo.load))),
        bookmarkButton("Update URL"),
        div(style="display:none", textInput("foo.bak", NULL))
    
      )}
    
    server <- function(input, output, session) {
      onBookmarked(function(url) {
        updateQueryString(url)
      })
      observeEvent(input$foo, { 
        if (is.null(input$foo)) {
          updateTextInput(session, "foo.bak", value="")
        } else {
          updateTextInput(session, "foo.bak", value=input$foo)
        }
      }, ignoreInit=TRUE, ignoreNULL = FALSE)
      observeEvent(input$foo.bak, {
        js$setfoo(items=as.list(strsplit(input$foo.bak,",")[[1]]))
      }, once=TRUE)
    }
    
    
    shinyApp(ui = ui, server = server, enableBookmarking = "server")
    
  • 0

    这是使用服务器端支持进行选择的更好解决方案 . 支持create = TRUE选项的重要步骤是使用 onRestored 使用用户创建的新值更新选项 .

    library(shiny)
    
    init.choices <- c("Choose From List or Type New Value"="")
    
    ui <- function(request) {
      fluidPage(
        titlePanel("Bookmarking Created Values"),
        selectizeInput("foo", NULL, 
                       choices=init.choices,
                       multiple=TRUE,
                       options=list(create=TRUE)),
        bookmarkButton("Update URL")
    
      )}
    
    server <- function(input, output, session) {
      updateSelectizeInput(session, "foo", choices=c(init.choices, rownames(mtcars)), server=TRUE)
      onBookmarked(function(url) {
        updateQueryString(url)
      })
      onRestored(function(state) {
        updateSelectizeInput(session, "foo", selected=state$input$foo, choices=c(init.choices, rownames(mtcars), state$input$foo), server=TRUE)
      })
    }
    
    
    shinyApp(ui = ui, server = server, enableBookmarking = "server")
    

相关问题