I am trying to build a simple app: in the first page is data collection with a renderdatatable to the right. I have a submit and edit buttons that do the job correctly, however, the delete button command does not delete the row (and store in the google datasheet). I managed to delete in the render table, but when reinitiating the app it was still there.
I can edit (and save) the changes, so it is not a permission problem. I tried many different approaches without success.
library(shiny)
library(shinythemes)
library(bslib)
library(bsicons)
library(tidyverse)
library(DT)
library(googlesheets4)
library(readxl)
# Load sheet (data.frame with columns: name, date, weight, height)
sheet_url <- "https://docs.google.com/spreadsheets/d/1jI9rwSMS4mi-EbHCDaT--gDETCpDNaadXK98lub0wVA/edit?gid=0#gid=0"
# Functions to save and load data
saveData <- function(data) {
data <- as.data.frame(data, stringsAsFactors = FALSE)
sheet_append(sheet_url, data)
}
loadData <- function() {
raw_data <- read_sheet(sheet_url) %>%
mutate(date = as_date(date)) %>%
arrange(date)
processed_data <- raw_data %>%
group_by(name) %>%
mutate(Nmonths = round((as.numeric(difftime(date, min(date), units = "days")) / 30), 1))
list(raw = raw_data, processed = processed_data)
}
# Define the fields we want to save from the form
fields <- c("name", "date", "weight", "height")
# UI
ui <- navbarPage(
theme = shinytheme("cerulean"),
title = "Baby growth",
tabPanel(
title = "Data entry",
sidebarLayout(
sidebarPanel(
selectInput("name", "Name", choices = c("John", "Mike")),
dateInput("date", "Registry date"),
numericInput("weight", "Weight", value = 0),
numericInput("height", "Height", value = 0),
actionButton("submit", "Submit"),
tags$hr(),
actionButton("edit", "Edit selected row"),
actionButton("save", "Save changes"),
actionButton("delete", "Delete selected row")
),
mainPanel(
DT::dataTableOutput("entry"),
tags$hr()
)
)
)
)
# Server
server <- function(input, output, session) {
# Load and preprocess baby data
data_list <- loadData()
raw_baby <- data_list$raw
processed_baby <- data_list$processed
# Initialize reactive values
rv <- reactiveValues(selected_row = NULL, data = raw_baby)
# Aggregate form data
formData <- reactive({
data <- sapply(fields, function(x) input[[x]], simplify = FALSE)
data <- as.data.frame(data, stringsAsFactors = FALSE)
data
})
# Submit button
observeEvent(input$submit, {
new_entry <- formData()
saveData(new_entry)
data_list <- loadData()
rv$data <- data_list$raw
showNotification("New entry added", type = "message")
})
# Edit button
observeEvent(input$edit, {
selected_row <- input$entry_rows_selected
if (length(selected_row) == 1) {
rv$selected_row <- selected_row
row <- rv$data[selected_row, ]
updateSelectInput(session, "name", selected = row$name)
updateDateInput(session, "date", value = row$date)
updateNumericInput(session, "weight", value = row$weight)
updateNumericInput(session, "height", value = row$height)
} else {
showNotification("Please select a single row to edit", type = "warning")
}
})
# Save button
observeEvent(input$save, {
selected_row <- rv$selected_row
if (!is.null(selected_row)) {
edited_entry <- formData()
edited_entry <- as.data.frame(edited_entry, stringsAsFactors = FALSE)
edited_entry$date <- edited_entry$date # Ensure date is character for saving
if (ncol(edited_entry) == ncol(rv$data)) {
rv$data[selected_row, ] <- edited_entry
# Save updated data to Google Sheets
range_write(sheet_url, data = rv$data, range = "A1", col_names = TRUE)
data_list <- loadData()
rv$data <- data_list$raw
rv$selected_row <- NULL
showNotification("Changes saved", type = "message")
} else {
showNotification("Error: Data format mismatch", type = "error")
}
}
})
# Delete button
observeEvent(input$delete, {
selected_row <- input$entry_rows_selected
if (length(selected_row) == 1) {
cat("Deleting row:", selected_row, "n") # Logging
rv$data <- rv$data[-selected_row, ]
# Save updated data to Google Sheets
range_write(sheet_url, data = rv$data, range = "A1", col_names = TRUE)
data_list <- loadData()
rv$data <- data_list$raw
rv$selected_row <- NULL
showNotification("Row deleted", type = "message")
} else {
showNotification("Please select a single row to delete", type = "warning")
}
})
# Render data table
output$entry <- DT::renderDataTable({
input$submit
input$save
input$delete
data_list <- loadData()
processed_baby <- data_list$processed
rv$data <- data_list$raw
processed_baby %>%
mutate(date = as.Date(date)) # Ensure date is displayed correctly
}, selection = 'single')
}
shinyApp(ui, server)