Open timelyportfolio opened 1 month ago
This helps, was cluelessly debugging shinylive apps previously.
I just finished a partial workaround, but I lose the ability to persist widgets in the viewer. Should be able to add some additional reactiveValues
to fix it though.
Combination of debouncing my renderdfViewer
and setting ide$viewer
to NULL
whenever the user swaps between viewer and environment pane.
mod_df_viewer.R
output$spreadsheet <- renderdfViewer({
shiny::req(ide$environment_selected, input$index, input$rows, input$columns)
df <- ide$environment_selected
# Logic for start index
start_index <- as.integer(input$index)
if(is.na(start_index) | start_index < 1){
start_index <- 1
}else if (start_index > nrow(df)){
start_index <- nrow(df)
}
# Logic for rows
row_count <- as.integer(input$rows)
if(row_count > 0){
# View first n rows
end_index <- min(start_index + row_count - 1, nrow(df))
df <- df[start_index:end_index, , drop = FALSE]
}else{
# View last n rows
start_index <- max(1, nrow(df) + row_count + 1)
df <- df[start_index:nrow(df), , drop = FALSE]
}
# Logic for columns
col_count <- as.integer(input$columns)
if (col_count > 0) {
# View first n columns
df <- df[, 1:min(col_count, ncol(df)), drop = FALSE]
} else {
# View last n columns
col_start <- max(1, ncol(df) + col_count + 1)
df <- df[, col_start:ncol(df), drop = FALSE]
}
if(is.null(df)){
df <- data.frame()
}
df_viewer(
data = df,
colHeaders = names(df),
width = "100%"
)
}) |>
debounce(1000)
control.R
shiny::observeEvent(input$tab_environment, {
ide$viewer <- NULL
ide$tab_control <- "environment"
})
So I should get a working solution that keeps the app functioning as I want so long as I flag for when the user is trying to view data using the df_viewer widget. In other instances when the user runs code with an htmlwidget (reactable, gt, ggplot, listviewer... small list for now). Another issue for another day to programmatically detect widgets, wrap them in their render function, and then rerun. Need to look more into how George is doing widgets in his R repl app, as the rerun might be unnecessary at this point.
Thanks again @timelyportfolio!
See https://github.com/ramnathv/htmlwidgets/issues/487 for reference and background. @jcheng5 @seanbirchall
Debugging
shinylive
Since
MessageChannel
replaces traditional Shiny websocket (easily tracked in browser debugging tools) inshinylive
/webR
, debugging can be a little more difficult. I discovered1)
options(shiny.trace = TRUE)
in the app will log to browser console which is helpful 2) manually hackingshinylive-inject-socket.txt
around line[https://github.com/posit-dev/shinylive/blob/main/src/assets/shinylive-inject-socket.txt#L62] by addingif(event.value && event.value.data) {console.log(JSON.parse(event.value.data))}
aftershinylive::export()
inshinylive-sw.js
provides the full streamPotential Partial Solution (at least locally for me in
shinylive
)While this helps in my local testing, I want to stress that the issue still eventually will appear if viewer is not cleared after first render. Before I was not able to get any rendered df_viewer, but it sounds like in the original issue that df_viewer would appear.
Moving lines to the end of
mod_df_viewer.R
seems to partially resolve what appears to be an asynchrony issue that happens in theshinylive
context. Oddly, when I added a line before thereq
(even a commented one) without changing the order of the code, then the problem also went away at least locally in ashinylive
context.Sean, if working correctly, you should be able to remove the manually added dependencies in lines.
Problem
The
shiny::req(ide$environment_selected, input$index, input$rows, input$columns)
in line leads to anull
data
message sent. Thenhtmlwidgets
line fails sincedata.deps
does not exist.