Assume that I have a reactive
which returns a data.frame
. I want some of my controls to take a dependency only on a subset of its columns, that is it should only fire, if values in any of the “relevant” columns (here rel_1
and rel_2
) change, while changes in the “irrelevant” columns (here irr_1
and irr_2
) should not trigger a refresh.
I thought creating a reactive
which returns only the relevant columns should do the trick, but the following code shows that all the buttons trigger a refresh of the verbatimTextOutput
. My expectation would be that a press to Change Irrelevant Columns would not trigger a refresh, because the values in the relevant columns remain unchanged.
library(shiny)
library(DT)
library(dplyr)
library(glue)
dat <- tibble(
rel_1 = LETTERS[1:3],
rel_2 = letters[1:3],
irr_1 = 1:3,
irr_2 = 101:103
)
ui <- fluidPage(
fluidRow(
column(
width = 4,
actionButton("chng_all", "Change All Columns")
),
column(
width = 4,
actionButton("chng_irr", "Change Irrelevant Columns")
),
column(
width = 4,
actionButton("chng_rel", "Change Relevant Columns")
)
),
fluidRow(
column(
width = 12,
DTOutput("tbl")
)
),
fluidRow(
column(
width = 12,
verbatimTextOutput("dbg")
)
)
)
server <- function(input, output, session) {
my_data <- reactiveVal(dat)
change_values <- function(data, cols) {
data %>%
mutate(
across(all_of(cols),
~ if (is.numeric(.x)) sample(100, 3) else sample(LETTERS, 3))
)
}
relevant_data <- reactive(
my_data() %>%
select(starts_with("rel"))
)
observe({
my_data(change_values(my_data(), c(paste0("irr_", 1:2),
paste0("rel_", 1:2))))
}) %>%
bindEvent(input$chng_all)
observe({
my_data(change_values(my_data(), paste0("irr_", 1:2)))
}) %>%
bindEvent(input$chng_irr)
observe({
my_data(change_values(my_data(), paste0("rel_", 1:2)))
}) %>%
bindEvent(input$chng_rel)
output$tbl <- renderDT(
datatable(my_data())
)
output$dbg <- renderPrint({
glue("Relevant Data Last Changed: {Sys.time()}")
}) %>%
bindEvent(relevant_data())
}
shinyApp(ui, server)