The code below replicates the problem. I have an app for users to update values and I need to refresh the page after they update the values because the colors need to update, but I haven’t been able to make it so pagination and ordering are preserved after the edits. GPT helped write a minimal working example but couldn’t solve the issue
ui <- fluidPage(
tags$head(
tags$script(HTML("
// Custom handler: update the select element and row color without redrawing.
Shiny.addCustomMessageHandler('updateDropdown', function(message) {
var tableEl = $('#demo_table table');
if (!tableEl.length) {
console.warn('Table element not found');
return;
}
var table = tableEl.DataTable();
var colIndex = 2; // Category column index.
var rowIndexes = table.rows().indexes().filter(function(idx) {
return table.row(idx).data()[0] == message.row;
});
if (rowIndexes.length > 0) {
var rowIndex = rowIndexes[0];
var cellNode = table.cell(rowIndex, colIndex).node();
$(cellNode).find('select').val(message.new_value);
$(table.row(rowIndex).node()).css('background-color', message.new_color);
}
});
"))
),
DTOutput("demo_table")
)
server <- function(input, output, session) {
# Create reactive data.
data <- reactiveVal(data.frame(
ID = 1:100,
Value = sample(1:1000, 100),
Category = sample(c("A", "B", "C"), 100, replace = TRUE),
stringsAsFactors = FALSE
))
# Helper function to create dropdown HTML.
createDropdown <- function(row_id, current) {
sprintf(
'<select data-row="%s" onchange="Shiny.setInputValue('category_change', {row: %s, value: this.value, nonce: Math.random()})">
<option value="A" %s>A</option>
<option value="B" %s>B</option>
<option value="C" %s>C</option>
</select>',
row_id, row_id,
ifelse(current == "A", "selected", ""),
ifelse(current == "B", "selected", ""),
ifelse(current == "C", "selected", "")
)
}
# Render the table only once by isolating the reactive data.
output$demo_table <- renderDT({
df <- isolate(data())
# Replace Category column with dropdown HTML.
df$Category <- sapply(df$ID, function(id) {
cat <- data()[data()$ID == id, "Category"]
createDropdown(id, cat)
})
datatable(
df,
escape = FALSE,
rownames = FALSE,
options = list(
pageLength = 10,
stateSave = TRUE,
order = list(list(1, "asc")),
rowCallback = JS("function(row, data, index) {
// Set hidden row id.
$(row).attr('data-row-id', data[0]);
// Color rows based on Value.
var val = parseInt(data[1]);
$(row).css('background-color', val > 500 ? 'lightblue' : 'white');
}")
)
)
}, server = TRUE)
proxy <- dataTableProxy("demo_table")
# When the dropdown value changes, update the data and replace the table data.
observeEvent(input$category_change, {
req(input$category_change)
info <- input$category_change
df <- data()
row_idx <- which(df$ID == info$row)
if (length(row_idx) == 0) return()
# Update the underlying data.
df$Category[row_idx] <- info$value
data(df)
# Rebuild the table data with the updated dropdown HTML.
new_df <- isolate(data())
new_df$Category <- sapply(new_df$ID, function(id) {
cur <- df[df$ID == id, "Category"]
createDropdown(id, cur)
})
# Update the table without resetting pagination.
replaceData(proxy, new_df, resetPaging = FALSE)
})
}
shinyApp(ui, server)
I tried tweaking the JS by directly updating the DOM but that didn’t work. GPT has given me many solutions but the problem always persists. It works if it’s a single page. I have looked at other posts – the problem in here is similar, but they don’t use JS as the option is not a dropdown, so I wasn’t able to replicate the solution
Blockquote