使用不同的输入小部件类型更新多个闪亮的应用程序输入
Update multiple shiny apps inputs with different input widget types
我设计了一个带有两个操作按钮的 Shiny 应用程序,Save
和 Clear
。当用户单击 Save
时,输入值将使用 Web 浏览器的本地存储进行存储。当用户单击 Clear
时,将清除输入和本地存储。
这些功能涉及使用 update...Input
更新多个输入。在这个例子中,我有三个输入都具有不同的小部件类型。我可以专门一一写出来,效果很好。但是,我想知道是否有更有效的方法来实现这一点,例如使用 for loop
或 lapply
。从这个 post () 看来,我可以使用 reactiveValuesToList
来获取所有输入。对我来说真正的挑战是如何为关联的输入小部件类型动态调用不同的 update...Input
函数?
如果您有任何建议,请告诉我。
### 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"),
textInput(inputId = "Text1", label = "Enter some texts")
),
mainPanel = mainPanel(
fluidRow(
numericInput(inputId = "Number1", label = "Enter a number", value = NA),
sliderInput(inputId = "Slider1", label = "Pick a number", min = 0, max = 100, value = 50),
actionButton("save", "Save", icon("save")),
actionButton("clear", "Clear", icon("stop"))
)
)
)
)
server <- function(input, output, session) {
observe({
if (input$save <= 0){
updateTextInput(session, inputId = "Text1", value = isolate(input$store)$Text1)
updateNumericInput(session, inputId = "Number1", value = isolate(input$store)$Number1)
updateSliderInput(session, inputId = "Slider1", value = isolate(input$store)$Slider1)
}
updateStore(session, name = "Text1", isolate(input$Text1))
updateStore(session, name = "Number1", isolate(input$Number1))
updateStore(session, name = "Slider1", isolate(input$Slider1))
})
observe({
if (input$clear > 0){
updateTextInput(session, inputId = "Text1", value = NA)
updateNumericInput(session, inputId = "Number1", value = NA)
updateSliderInput(session, inputId = "Slider1", value = 50)
updateStore(session, name = "Text1", value = NA)
updateStore(session, name = "Number1", value = NA)
updateStore(session, name = "Slider1", value = 50)
}
})
}
shinyApp(ui, server)
很遗憾,shiny
中没有通用的 updateInput
函数。仍然可以构建一个将特定名称标识为特定输入类型的包装器,但这也需要知道允许或不允许哪个参数。例如,updateActionButton
没有 value
或 choices
作为参数,因此我们需要大量的 if 语句。
一种可能的解决方法是利用 renderUI
并直接传递存储的值。唯一的缺点是某些函数如 SliderInput
在某些参数为 NULL 时会抛出错误,因此需要使用 if 语句为应用程序首次运行指定默认值。或者,可以执行一次模拟应用程序以仅填充第一个值。
代码:
library(shiny)
library(shinyStore)
library(tidyverse)
ui <- fluidPage(
initStore("store", "shinyStore-ex1"),
uiOutput('ui_all'))
server <- function(input, output, session) {
output$ui_all <- renderUI({
tagList(
headerPanel("shinyStore Example"),
sidebarLayout(
sidebarPanel = sidebarPanel(
textInput(inputId = "Text1", label = "Enter some texts",value = input$store$Text1)
),
mainPanel = mainPanel(
fluidRow(
numericInput(inputId = "Number1", label = "Enter a number", value = input$store$Number1),
sliderInput(inputId = "Slider1", label = "Pick a number", min = 0, max = 100, value = if(is.null(input$store$Slider1)){50} else{input$store$Slider1}),
actionButton("save", "Save", icon("save")),
actionButton("clear", "Clear", icon("stop"))
)
)
))
})
input_nms <- map(c('Text', 'Number', 'Slider'), ~str_c(.x, 1:1)) %>%
reduce(c)
#or if every type of input is repeteated n different times.
# input_nms <- map2(c('Text', 'Number', 'Slider'), c(n1, n2, n3), ~str_c(.x, 1:.y)) %>%
# reduce(c)
observeEvent(input$save, {
input_nms %>%
walk(~updateStore(session = session, name = .x, value = isolate(input[[.x]])))
session$reload() #to force the UI to render again with the new values
})
observeEvent(input$clear, {
input_nms %>%
walk2(c(NA, NA, 50), ~updateStore(session = session, name = .x, value = .y))
})
}
shinyApp(ui, server)
我设计了一个带有两个操作按钮的 Shiny 应用程序,Save
和 Clear
。当用户单击 Save
时,输入值将使用 Web 浏览器的本地存储进行存储。当用户单击 Clear
时,将清除输入和本地存储。
这些功能涉及使用 update...Input
更新多个输入。在这个例子中,我有三个输入都具有不同的小部件类型。我可以专门一一写出来,效果很好。但是,我想知道是否有更有效的方法来实现这一点,例如使用 for loop
或 lapply
。从这个 post () 看来,我可以使用 reactiveValuesToList
来获取所有输入。对我来说真正的挑战是如何为关联的输入小部件类型动态调用不同的 update...Input
函数?
如果您有任何建议,请告诉我。
### 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"),
textInput(inputId = "Text1", label = "Enter some texts")
),
mainPanel = mainPanel(
fluidRow(
numericInput(inputId = "Number1", label = "Enter a number", value = NA),
sliderInput(inputId = "Slider1", label = "Pick a number", min = 0, max = 100, value = 50),
actionButton("save", "Save", icon("save")),
actionButton("clear", "Clear", icon("stop"))
)
)
)
)
server <- function(input, output, session) {
observe({
if (input$save <= 0){
updateTextInput(session, inputId = "Text1", value = isolate(input$store)$Text1)
updateNumericInput(session, inputId = "Number1", value = isolate(input$store)$Number1)
updateSliderInput(session, inputId = "Slider1", value = isolate(input$store)$Slider1)
}
updateStore(session, name = "Text1", isolate(input$Text1))
updateStore(session, name = "Number1", isolate(input$Number1))
updateStore(session, name = "Slider1", isolate(input$Slider1))
})
observe({
if (input$clear > 0){
updateTextInput(session, inputId = "Text1", value = NA)
updateNumericInput(session, inputId = "Number1", value = NA)
updateSliderInput(session, inputId = "Slider1", value = 50)
updateStore(session, name = "Text1", value = NA)
updateStore(session, name = "Number1", value = NA)
updateStore(session, name = "Slider1", value = 50)
}
})
}
shinyApp(ui, server)
很遗憾,shiny
中没有通用的 updateInput
函数。仍然可以构建一个将特定名称标识为特定输入类型的包装器,但这也需要知道允许或不允许哪个参数。例如,updateActionButton
没有 value
或 choices
作为参数,因此我们需要大量的 if 语句。
一种可能的解决方法是利用 renderUI
并直接传递存储的值。唯一的缺点是某些函数如 SliderInput
在某些参数为 NULL 时会抛出错误,因此需要使用 if 语句为应用程序首次运行指定默认值。或者,可以执行一次模拟应用程序以仅填充第一个值。
代码:
library(shiny)
library(shinyStore)
library(tidyverse)
ui <- fluidPage(
initStore("store", "shinyStore-ex1"),
uiOutput('ui_all'))
server <- function(input, output, session) {
output$ui_all <- renderUI({
tagList(
headerPanel("shinyStore Example"),
sidebarLayout(
sidebarPanel = sidebarPanel(
textInput(inputId = "Text1", label = "Enter some texts",value = input$store$Text1)
),
mainPanel = mainPanel(
fluidRow(
numericInput(inputId = "Number1", label = "Enter a number", value = input$store$Number1),
sliderInput(inputId = "Slider1", label = "Pick a number", min = 0, max = 100, value = if(is.null(input$store$Slider1)){50} else{input$store$Slider1}),
actionButton("save", "Save", icon("save")),
actionButton("clear", "Clear", icon("stop"))
)
)
))
})
input_nms <- map(c('Text', 'Number', 'Slider'), ~str_c(.x, 1:1)) %>%
reduce(c)
#or if every type of input is repeteated n different times.
# input_nms <- map2(c('Text', 'Number', 'Slider'), c(n1, n2, n3), ~str_c(.x, 1:.y)) %>%
# reduce(c)
observeEvent(input$save, {
input_nms %>%
walk(~updateStore(session = session, name = .x, value = isolate(input[[.x]])))
session$reload() #to force the UI to render again with the new values
})
observeEvent(input$clear, {
input_nms %>%
walk2(c(NA, NA, 50), ~updateStore(session = session, name = .x, value = .y))
})
}
shinyApp(ui, server)