我想制作一个仪表板来跟踪健身活动。 我使用 googlesheets 作为后端存储。
当应用程序打开时,它会画出今天/昨天的所有活动。 /昨天之前。
应用程序的第一个屏幕显示了今天可用活动的所有开关 根据 googlesheet 数据源,开关已预加载其“当前状态”。
还有另一个切换键可以在今天/昨天之间切换。 /前一天。
目前,当我在不同日期之间交换时,当我切换回当天时,我所做的任何更改(例如今天的活动切换)都不再存在。
感觉我需要一些反应性对象 最初只是原始状态(从 googlesheets 下载) 但我希望每次按下开关时我对开关所做的更改(针对每天的每个活动)都会更新它。
我的目标是仅在点击“上传”按钮后才将更改上传到 googlesheets(但我已经涵盖了)。
library(tidyverse)
library(shiny)
library(shinyWidgets)
timeframes <-
tribble(
~date_name, ~date,
"Today", today()
, "Yesterday", today()-1
, "Day before yesterday", today()-2
)
pre_assignment_vector <-
tibble::tribble(
~feature, ~date_name, ~value,
"bike_into_coworking_space", "Day before yesterday", FALSE,
"bike_into_coworking_space", "Today", FALSE,
"bike_into_coworking_space", "Yesterday", TRUE,
"yoga", "Day before yesterday", FALSE,
"yoga", "Today", FALSE,
"yoga", "Yesterday", TRUE
) %>%
mutate(value_name = paste0(feature, "_", snakecase::to_snake_case(date_name), "_status"),
input_id_destination = paste0(feature, "_switch")
)
assignment_vector <-
pre_assignment_vector %>%
filter(date_name == "Today")
map2(assignment_vector$value_name, assignment_vector$value, ~assign(.x, .y, envir = .GlobalEnv))
###################################################################
reactive_store_of_values_obj <- reactive(pre_assignment_vector)
###################################################################
# a function for when the date toggle is pressed
update_switches_to_date_selected <- function(reactive_store_of_values_obj, timeframe_selected) {
# timeframe_selected <- "Yesterday"
# reactive_store_of_values_obj <- pre_assignment_vector
values_to_update_to <-
reactive_store_of_values_obj %>%
filter(date_name == timeframe_selected)
status_vals <- values_to_update_to
map2(status_vals$input_id_destination, status_vals$value, ~updateSwitchInput(inputId = .x, value = as.logical(.y)))
}
###################################################################
# a function to update the persistent "stor of values" object whenever any toggles are pressed.
# using hte date toggle input varable to determine the day
update_the_reactive_store_of_values_obj <- function(reactive_store_of_values_obj
, timeframe_selected = input$timeframe_selected
, yoga_switch = input$yoga_switch
, bike_into_coworking_space_switch = input$bike_into_coworking_space_switch) {
# reactive_store_of_values_obj <- pre_assignment_vector
# timeframe_selected <- "Yesterday"
# yoga_switch <- yoga_today_status
# bike_into_coworking_space_switch <- bike_into_coworking_space_today_status
new_values_from_inputs <-
tibble(yoga_switch = yoga_switch,
bike_into_coworking_space_switch = bike_into_coworking_space_switch) %>%
gather(input_id_destination, new_value) %>%
mutate(date_name = timeframe_selected)
reactive_store_of_values_obj %>%
left_join(new_values_from_inputs, by = join_by(date_name, input_id_destination)) %>%
mutate(value = coalesce(new_value, value)) %>%
select(-new_value)
}
###################################################################
ui <- fluidPage(
mainPanel(
fluidRow(
h3("Timeframe"),
sliderTextInput(inputId = "timeframe_selected",
label = NULL,
choices = rev(timeframes$date_name),
selected = timeframes$date_name[1])
),
fluidRow(
column(width = 2, h4("Yoga")),
column(width = 1, prettySwitch(inputId = "yoga_switch", label = NULL, value = as.logical(yoga_today_status))),
),
fluidRow(
column(width = 2, h4("Bike into Coworking Space")),
column(width = 1, prettySwitch(inputId = "bike_into_coworking_space_switch", label = NULL, value = as.logical(bike_into_coworking_space_today_status)))
)
)
)
server <- function(input, output) {
observeEvent(ignoreInit = TRUE, input$timeframe_selected, {
# update inputs to the newly selected date's values
update_switches_to_date_selected(reactive_store_of_values_obj = reactive_store_of_values_obj(), timeframe_selected = input$timeframe_selected)
})
###################################################################
all_inputs_watch_list <- reactive(
list(
input$yoga_switch
, input$bike_into_coworking_space_switch
))
observeEvent(ignoreInit = TRUE, all_inputs_watch_list(), {
print("switch used")
reactive_store_of_values_obj <- reactive(update_the_reactive_store_of_values_obj(reactive_store_of_values_obj()))
})
}
shinyApp(ui = ui, server = server)
我得到了一些解决方案的帮助(我还不太完全理解它,但它有效。
在服务器内,我需要像这样启动持久反应对象......
reactive_object <- reactiveValues(store_of_values = NULL)
observe({reactive_object$store_of_values <- pre_assignment_vector})
然后,所有对“reactive_store_of_values_obj()”的引用都可以替换为“reactive_object$store_of_values”
EG
update_switches_to_date_selected(reactive_store_of_values_obj = reactive_object$store_of_values, timeframe_selected = input$timeframe_selected)
reactive_object$store_of_values <- update_the_reactive_store_of_values_obj(reactive_object$store_of_values, input$timeframe_selected, input)
这是完整的代码,并进行了这些更正
library(tidyverse)
library(shiny)
library(shinyWidgets)
timeframes <-
tribble(
~date_name, ~date,
"Today", today()
, "Yesterday", today()-1
, "Day before yesterday", today()-2
)
pre_assignment_vector <-
tibble::tribble(
~feature, ~date_name, ~value,
"bike_into_coworking_space", "Day before yesterday", FALSE,
"bike_into_coworking_space", "Today", FALSE,
"bike_into_coworking_space", "Yesterday", TRUE,
"yoga", "Day before yesterday", FALSE,
"yoga", "Today", FALSE,
"yoga", "Yesterday", TRUE
) %>%
mutate(value_name = paste0(feature, "_", snakecase::to_snake_case(date_name), "_status"),
input_id_destination = paste0(feature, "_switch")
)
assignment_vector <-
pre_assignment_vector %>%
filter(date_name == "Today")
map2(assignment_vector$value_name, assignment_vector$value, ~assign(.x, .y, envir = .GlobalEnv))
###################################################################
# a function for when the date toggle is pressed
update_switches_to_date_selected <- function(reactive_store_of_values_obj, timeframe_selected) {
# timeframe_selected <- "Yesterday"
# reactive_store_of_values_obj <- pre_assignment_vector
values_to_update_to <-
reactive_store_of_values_obj %>%
filter(date_name == timeframe_selected)
status_vals <- values_to_update_to
map2(status_vals$input_id_destination, status_vals$value, ~updateSwitchInput(inputId = .x, value = as.logical(.y)))
}
###################################################################
# a function to update the persistent "stor of values" object whenever any toggles are pressed.
# using hte date toggle input varable to determine the day
update_the_reactive_store_of_values_obj <- function(reactive_store_of_values_obj
, timeframe_selected
, input) {
# timeframe_selected <- "Yesterday"
# reactive_store_of_values_obj <- pre_assignment_vector
#
# input <- list(
# yoga_switch = yoga_today_status,
# bike_into_coworking_space_switch = bike_into_coworking_space_today_status
# )
new_values_from_inputs <-
tibble(yoga_switch = input$yoga_switch,
bike_into_coworking_space_switch = input$bike_into_coworking_space_switch) %>%
gather(input_id_destination, new_value) %>%
mutate(date_name = timeframe_selected)
reactive_store_of_values_obj %>%
left_join(new_values_from_inputs, by = join_by(date_name, input_id_destination)) %>%
mutate(value = coalesce(new_value, value)) %>%
select(-new_value)
}
###################################################################
ui <- fluidPage(
mainPanel(
fluidRow(
h3("Timeframe"),
sliderTextInput(inputId = "timeframe_selected",
label = NULL,
choices = rev(timeframes$date_name),
selected = timeframes$date_name[1])
),
fluidRow(
column(width = 2, h4("Yoga")),
column(width = 1, prettySwitch(inputId = "yoga_switch", label = NULL, value = as.logical(yoga_today_status))),
),
fluidRow(
column(width = 2, h4("Bike into Coworking Space")),
column(width = 1, prettySwitch(inputId = "bike_into_coworking_space_switch", label = NULL, value = as.logical(bike_into_coworking_space_today_status)))
)
)
)
server <- function(input, output) {
reactive_object <- reactiveValues(store_of_values = NULL)
observe({reactive_object$store_of_values <- pre_assignment_vector})
observeEvent(ignoreInit = TRUE, input$timeframe_selected, {
# update inputs to the newly selected date's values
update_switches_to_date_selected(reactive_store_of_values_obj = reactive_object$store_of_values, timeframe_selected = input$timeframe_selected)
})
###################################################################
all_inputs_watch_list <- reactive(
list(
input$yoga_switch
, input$bike_into_coworking_space_switch
))
observeEvent(ignoreInit = TRUE, all_inputs_watch_list(), {
print("switch used")
reactive_object$store_of_values <- update_the_reactive_store_of_values_obj(reactive_object$store_of_values, input$timeframe_selected, input)
})
}
shinyApp(ui = ui, server = server)