www*_*www 4 r shiny shinystore
这是我之前问过的这个问题的后续问题(如果选择取决于另一个输入,shinyStore 无法恢复 selectizeInput 的选定值)。我已经找到答案(/sf/answers/4780315921/)。然而,现在我意识到我的答案并不完整。请看下面的代码。这与我之前的问答相同,只不过我设置server = TRUE为第一个updateSelectizeInput,这使得本地存储无法工作。如果我能使用那就太好了,server = TRUE因为在我的现实世界示例中,我的选择selectizeInput很多。
### This script creates an example of the shinystore package
# Load packages
library(shiny)
library(shinyStore)
ui <- fluidPage(
headerPanel("shinyStore Example"),
sidebarLayout(
sidebarPanel = sidebarPanel(
initStore("store", "shinyStore-ex1"),
selectizeInput(inputId = "Select1", label = "Select A Number",
choices = as.character(1:3),
options = list(
placeholder = 'Please select a number',
onInitialize = I('function() { this.setValue(""); }'),
create = TRUE
))
),
mainPanel = mainPanel(
fluidRow(
selectizeInput(inputId = "Select2",
label = "Select A Letter",
choices = character(0),
options = list(
placeholder = 'Please select a number in the sidebar first',
onInitialize = I('function() { this.setValue(""); }'),
create = TRUE
)),
actionButton("save", "Save", icon("save")),
actionButton("clear", "Clear", icon("stop"))
)
)
)
)
server <- function(input, output, session) {
dat <- data.frame(
Number = as.character(rep(1:3, each = 3)),
Letter = letters[1:9]
)
observeEvent(input$Select1, {
updateSelectizeInput(session, inputId = "Select2",
choices = dat$Letter[dat$Number %in% input$Select1],
# Add server = TRUE make the local storage not working
server = TRUE)
}, ignoreInit = TRUE)
observe({
if (input$save <= 0){
updateSelectizeInput(session, inputId = "Select1", selected = isolate(input$store)$Select1)
}
})
observe({
if (input$save <= 0){
req(input$Select1)
updateSelectizeInput(session, inputId = "Select2", selected = isolate(input$store)$Select2)
}
})
observe({
if (input$save > 0){
updateStore(session, name = "Select1", isolate(input$Select1))
updateStore(session, name = "Select2", isolate(input$Select2))
}
})
observe({
if (input$clear > 0){
updateSelectizeInput(session, inputId = "Select1",
options = list(
placeholder = 'Please select a number',
onInitialize = I('function() { this.setValue(""); }'),
create = TRUE
))
updateSelectizeInput(session, inputId = "Select2",
choices = character(0),
options = list(
placeholder = 'Please select a number in the sidebar first',
onInitialize = I('function() { this.setValue(""); }'),
create = TRUE
))
updateStore(session, name = "Select1", NULL)
updateStore(session, name = "Select2", NULL)
}
})
}
shinyApp(ui, server)
Run Code Online (Sandbox Code Playgroud)
最简单的解决方案之一可以是:
只需将您的observeEvent(input$Select1, ...观察者更改为这个即可
once_flag <- reactiveVal(TRUE)
observeEvent(input$Select1, {
updateSelectizeInput(
session, inputId = "Select2", server = TRUE,
choices = dat$Letter[dat$Number %in% input$Select1],
selected = if(once_flag()) input$store$Select2 else NULL
)
once_flag(FALSE)
}, ignoreInit = TRUE)
Run Code Online (Sandbox Code Playgroud)
你就完成了。多么简单啊!一切都在同一个中解决observeEvent,只需一次更新调用。这once_flag是为了确保设定Select2值仅一次。第二次及以后更改时Select1,我们不会设置 的值Select2。
感谢@ismirsehregal等其他用户的更正,所以我可以想出上面的简单解决方案。由于shinyStore直接为您提供了这个包装器 API input$store,因此您不需要像我下面那样编写 API,但工作流程和后面的内容是相同的。如果您对该解决方案的工作原理感兴趣,请继续阅读。
我们要解决的最大问题是server = TRUE,阅读帮助文件我们知道store choices on the server-side, and load the select options dynamically on searching。这意味着您的客户端(UI)一开始并不知道有哪些选项。HTML5 localstore(shinystore背后的东西)是一种客户端技术,它只能改变一开始就存在的东西。如果启动应用程序时未给出选项,则无法更改它。这就是它失败的原因。
如果select2是在 后/基于 更新的,我们可以在结算后select1检索该值,然后将该值分配给 吗?shinystoreselect1select2
答案是否定的,也是肯定的。否,因为原始版本(不是真的,请参阅评论,但下面有助于理解闪亮商店的工作原理)。是的,是因为如果你了解html5本地存储和Shiny的JS-R如何通信,我们就可以编写自己的API来获取值。shinystore没有为您提供任何用于 R-Javascript 通信的 API 来检索值。它只允许设置,不允许获取
这是工作流程:
select1select1更新, updateselect2的选项select2并从 JS 发送到 R。(shinyStore您可以通过(输入 ID)访问它input$store$xxx。下面我手动编写代码来展示他们如何将客户端值返回为input值。)select2所选的选项让我们看看它在代码中是如何工作的:
observeEvent(input$Select1, {
# detect 1 changed
# send signal to client to get stored 2's value
session$sendCustomMessage(
"shinyStore_getvalue",
list(
namespace = "shinyStore-ex1",
key = "Select2"
)
)
# updated 2's choices based on 1
updateSelectizeInput(session, inputId = "Select2",
choices = dat$Letter[dat$Number %in% input$Select1],
server = TRUE)
}, ignoreInit = TRUE)
Run Code Online (Sandbox Code Playgroud)
R-JS 如何通信,请阅读此页面。
Shiny.addCustomMessageHandler('shinyStore_getvalue', function(data) {
var val = localStorage.getItem(`${data.namespace}\\${data.key}`);
if(val === null) return false;
val = JSON.parse(val);
if(val.data === undefined) return false;
Shiny.setInputValue(`shinystore_${data.key}`, val.data);
});
Run Code Online (Sandbox Code Playgroud)
获取查询到的shinystore值并将其作为输入值发送给Rshiny,可以直接使用observe。这里不再解释详细信息,如果您想了解更多信息,请再次阅读上面的链接。
observeEvent(input$shinystore_Select2, {
updateSelectizeInput(
session,
inputId = "Select2",
choices = dat$Letter[dat$Number %in% input$Select1],
server = TRUE,
selected = input$shinystore_Select2
)
}, once = TRUE)
Run Code Online (Sandbox Code Playgroud)
添加once仅设置一次值。
详细解决方案的完整代码
library(shiny)
library(shinyStore)
ui <- fluidPage(
headerPanel("shinyStore Example"),
tags$script(HTML(
'
Shiny.addCustomMessageHandler(\'shinyStore_getvalue\', function(data) {
var val = localStorage.getItem(`${data.namespace}\\\\${data.key}`);
if(val === null) return false;
val = JSON.parse(val);
if(val.data === undefined) return false;
Shiny.setInputValue(`shinystore_${data.key}`, val.data);
});
'
)),
sidebarLayout(
sidebarPanel = sidebarPanel(
initStore("store", "shinyStore-ex1"),
selectizeInput(inputId = "Select1", label = "Select A Number",
choices = as.character(1:3),
options = list(
placeholder = 'Please select a number',
onInitialize = I('function() { this.setValue(""); }'),
create = TRUE
))
),
mainPanel = mainPanel(
fluidRow(
selectizeInput(inputId = "Select2",
label = "Select A Letter",
choices = character(0),
options = list(
placeholder = 'Please select a number in the sidebar first',
onInitialize = I('function() { this.setValue(""); }'),
create = TRUE
)),
actionButton("save", "Save", icon("save")),
actionButton("clear", "Clear", icon("stop"))
)
)
)
)
server <- function(input, output, session) {
dat <- data.frame(
Number = as.character(rep(1:3, each = 3)),
Letter = letters[1:9]
)
observeEvent(input$Select1, {
# detect 1 changed
# send signal to client to get stored 2's value
session$sendCustomMessage(
"shinyStore_getvalue",
list(
namespace = "shinyStore-ex1",
key = "Select2"
)
)
# # updated 2's choices based on 1
updateSelectizeInput(session, inputId = "Select2",
choices = dat$Letter[dat$Number %in% input$Select1],
server = TRUE)
}, ignoreInit = TRUE)
observeEvent(input$shinystore_Select2, {
updateSelectizeInput(
session,
inputId = "Select2",
choices = dat$Letter[dat$Number %in% input$Select1],
server = TRUE,
selected = input$shinystore_Select2
)
}, once = TRUE)
observe({
if (input$save <= 0){
updateSelectizeInput(session, inputId = "Select1", selected = isolate(input$store)$Select1)
}
})
observe({
if (input$save <= 0){
req(input$Select1)
updateSelectizeInput(session, inputId = "Select2", selected = isolate(input$store)$Select2)
}
})
observe({
if (input$save > 0){
updateStore(session, name = "Select1", isolate(input$Select1))
updateStore(session, name = "Select2", isolate(input$Select2))
}
})
observe({
if (input$clear > 0){
updateSelectizeInput(session, inputId = "Select1",
options = list(
placeholder = 'Please select a number',
onInitialize = I('function() { this.setValue(""); }'),
create = TRUE
))
updateSelectizeInput(session, inputId = "Select2",
choices = character(0),
options = list(
placeholder = 'Please select a number in the sidebar first',
onInitialize = I('function() { this.setValue(""); }'),
create = TRUE
))
updateStore(session, name = "Select1", NULL)
updateStore(session, name = "Select2", NULL)
}
})
}
shinyApp(ui, server)
Run Code Online (Sandbox Code Playgroud)