rhandsontable
rhandsontable copied to clipboard
Changing an RHOT table's dimensions loses all input and triggers hot_to_r()
In order to handle different resolutions I used javascript to get viewport dimensions and passed that as an option to rhandsontable()
as height=(input$dimension[1]*.45)
. However while using this anything that causes RHOT to resize itself appears to cause a re-render that drops all user input. This triggers hot_to_r()
as well.
Hi @D3SL I think I've had a lot of the same problems as yourself with dynamically changing the height of a rhandsontable. I wondered if you'd made any decent headway? I have managed to solve the dropping of all user changes to the table issue using a server side reactive variable. however the whole handsontable is re rendered whenever the window is resized.
Below is my minimal example of a resizing hot where user changes persist
library(shiny)
library(shinymaterial)
library(tibble)
library(magrittr)
library(rhandsontable)
#custom js to add input$dimension to shiny that updates on window resize
custom_js_table_height <- '
var dimension = [0, 0];
$(document).on("shiny:connected", function(e) {
dimension[0] = window.innerWidth;
dimension[1] = window.innerHeight;
Shiny.onInputChange("dimension", dimension);
});
$(window).resize(function(e) {
dimension[0] = window.innerWidth;
dimension[1] = window.innerHeight;
Shiny.onInputChange("dimension", dimension);
});
'
ui <-
material_page(
title = "A long rhnadsontable with window resizing",
#add custom js
tags$head(tags$script(HTML(
custom_js_table_height
))),
material_card(
title = "Here is my table",
rhandsontable::rHandsontableOutput("iris", height = "100%", width = "100%"),
h6("And here is a ui element after")
)
)
server <- function(input, output) {
#define reactive values, one for server side data storage, one for the
#server side height of the hands on table
reactive_iris <- reactiveValues(data = iris)
reactive_hot_height <- reactiveValues(height = 100)
#whenever the table changes, check if identical to server side, if not
#update server side
observeEvent(input$iris, {
current_table <- input$iris %>% hot_to_r() %>% as_tibble()
old_stored_table <- reactive_iris[["data"]] %>% as_tibble()
if (!identical(current_table, old_stored_table)) {
cat("updated server side df\n")
reactive_iris[["data"]] <- current_table
}
})
#when window dimension changes, update server side height.
#One downside is having to estimate the number of pixels to remove from the
#total window height, this would need updating any time the ui updated
observeEvent(input$dimension, {
reactive_hot_height[["height"]] <- input$dimension[2] - 230
})
#render the table, table is rerendered every time reactive_iris or
#reactive_hot_height changes
#
#additional rows added
output$iris <- ({
renderRHandsontable({
cat("table rendered\n")
rhandsontable(reactive_iris[["data"]],
rowHeaders = TRUE,
height = reactive_hot_height[["height"]],
) %>%
hot_table(stretchH = "all")
})
})
}
shinyApp(ui = ui, server = server)
Hi @D3SL I think I've had a lot of the same problems as yourself with dynamically changing the height of a rhandsontable. I wondered if you'd made any decent headway? I have managed to solve the dropping of all user changes to the table issue using a server side reactive variable. however the whole handsontable is re rendered whenever the window is resized.
To be honest I just left it with a generically 1080p friendly size and forgot about this. As near as I could tell the problem was that upon re-rendering the RHOT with its new size it showed up blank, which was registered as if it were a user input, and the new blank table was saved overwriting all of the user's actual input.
If I'm reading your code right what you do is save the initial state of the table to old_stored_table
when the app is first loaded and anytime a new input is detected you compare current_rhot
to old_stored_table
, updating old_stored_table
if the two aren't the same.
If your method works it means I'm wrong about why resizing the table is wiping out all saved data from user inputs, because as soon as the user inputs data which is saved to old_stored_table
a new blank table would pass the !identical()
test you use and still overwrite old_stored_table
.