Incorrect change reporting when initial data has 0 rows
When a rhandsontable widget is initialized with defined columns but 0 rows, and then rows are added, the changes reported to the server are incorrect. The changes always show the change happened in the last numeric column of the new row. I'm not sure if this happens when rows are added by right-clicking, but it definitely occurs when minSpareRows adds rows automatically.
I spent a while tracking it down and this is because the handsontable afterChange event passes undefined as the old value and null as the new value. Since undefined !== null the test on line 121 of rhandsontable.js passes, the change is considered valid, and it's sent to the R server.
The behavior is pretty convoluted to reproduce, but here goes:
library(shiny)
library(rhandsontable)
data <- list(
d1 = tibble::tibble(
x = numeric(),
y = numeric(),
z = integer(),
ch = character(),
ch2 = character(),
log = logical()
),
d2 = tibble::tibble(
x = runif(10),
y = runif(10, 5, 10),
z = sample(1:5, 10, replace = TRUE),
ch = sample(LETTERS, 10),
ch2 = sample(letters, 10),
log = as.logical(c(
sample(0:1, 8, replace = TRUE),
rep(NA, 2)
))
)
)
shinyApp(
ui = fluidPage(
titlePanel("HOT changes glitch reprex"),
helpText(
"Watch the status of input$hot$changes with the 2 different datasets.
Both datasets have the same structure, but one is initialized with
0 rows while the other has 10 to start. Both use minSpareRows = 1."
),
helpText(
"When the minSpareRows option adds a row to dataset d1, the changes
reported are incorrect. The change is reported for the last numeric
column in the blank row that was added automatically."
),
helpText(
"When the blank row is added to dataset d2, the changes
reported are correct."
),
fluidRow(
column(
width = 8,
selectInput("pick", "Choose Data", choices = c("d1", "d2"), selected = "d1"),
rHandsontableOutput("hot", width = "80%")
),
column(
width = 4,
helpText("input$hot$changes:"),
verbatimTextOutput("hot_changes"),
tags$br(),
helpText("change description:"),
textOutput("hot_ch_descr"),
tags$br(),
helpText("click below to view input$hot"),
actionButton("hot_modal", "View")
)
)
),
server = function(input, output, session) {
output$hot <- renderRHandsontable({
DF = data[[input$pick]]
rhandsontable(DF, debug = 2) %>%
hot_table(
highlightCol = TRUE,
highlightRow = TRUE,
minSpareRows = 1
)
})
output$hot_changes <- renderPrint({
req(input$hot)
str(input$hot$changes)
})
output$hot_ch_descr <- renderPrint({
req(input$hot$changes$changes)
row <- input$hot$changes$changes[[1]][[1]] + 1
col <- input$hot$changes$changes[[1]][[2]] + 1
col_nm <- isolate({
names(data[[input$pick]])[col]
})
sprintf("Change registered in row %i column %s", row, col_nm)
})
output$str_hot <- renderPrint({
req(input$hot)
str(input$hot)
})
observeEvent(input$hot_modal, {
req(input$hot)
showModal(modalDialog(
title = "input$hot:",
verbatimTextOutput("str_hot"),
easyClose = TRUE
))
})
}
)
I will submit a PR with a fix shortly.
See #373