Pre-Select Rows of a Dynamic Dt in Shiny

Pre-select rows of a dynamic DT in shiny

To allow reactive on selected evaluation, you need to call datatable from within renderDataTable:

output$x1 = renderDataTable(
datatable( data(),
selection = list(mode = 'multiple', selected = all_rows())),
server = FALSE)

Dynamically pre-select row using DT in shiny

It is written in the other post to wrap it within datatable() then it works :)

output$myTable <- DT::renderDataTable ({
datatable(
mtcars[,1:5],
rownames = T,
filter = "top",
selection = list(mode='multiple',
selected = selRows$row)
)
})

How to pre-select rows in Shiny DT datatables

This feature has been added to DT (>= 0.1.3). Examples:

library(shiny)
if (packageVersion('DT') < '0.1.3') devtools::install_github('rstudio/DT')
library(DT)
shinyApp(
ui = fluidPage(
fluidRow(
h1('Client-side processing'),
DT::dataTableOutput('x1'),
h1('Server-side processing'),
DT::dataTableOutput('x2')
)
),
server = function(input, output, session) {
output$x1 = DT::renderDataTable(
iris, server = FALSE,
selection = list(mode = 'multiple', selected = c(1, 3, 8, 12))
)
output$x2 = DT::renderDataTable(
iris, server = TRUE,
selection = list(mode = 'multiple', selected = rownames(iris)[c(1, 3, 8, 12)])
)
}
)

R Shiny - Pre-selection of rows in Select extension for Datatables

There's no select.rows option. You can use a callback:

output[["table"]] <- renderDT({
datatable(
dat,
callback = JS("table.rows([0,1,2]).select();"),
options = list(select = list(
style = "multi",
selector = "td:not(.notselectable)")),
extensions = "Select", selection = "none")
}, server = FALSE)

Shiny DT - Select row after selected row by using a button

I have a feeling (could be wrong) that this might be a case of XY Problem trap i.e. you are asking for help with your attempt at solving a problem rather than with the underlying problem itself. If this is the case, you are better off asking another question explaining your core requirement which might yield a simpler overall solution. Although my solution is pretty straightforward the whole thing just feels like an unnecessary complication.

Anyways, here's one way to do this. You can get the current order of rows on the datatable using input$tableId_rows_all which gives the indices of rows on all pages (after the table is filtered by the search strings). output$test shows this order in real-time. Now you just need to cycle through this order every time user hits next_doc action button.

This solution will work even if you reorder your rows or manually change selected row.

library(shiny)
library(DT)

ui <- tagList(
ui <- basicPage(
h2("My Table"),
DT::dataTableOutput("DT_show_docs"),
textOutput("printScore"),
actionButton("next_doc", "Next Document"),
verbatimTextOutput("test")
)
)

# Server
server <- function(input, output, session) {

doc_overview <- reactive({
df <- data.frame(Doc_ID = seq(1,12),
Filename = paste0("File_",seq(1,12)),
Score = sample(1:10,12,replace=TRUE),
Approved = rep(c("No", "Yes"), times = c(5,7)),
Date = rep(seq(as.Date("2018/01/01"), as.Date("2018/1/10"), "days"), length.out=12))
return(df)
})

output$DT_show_docs <- renderDataTable({

DT::datatable(doc_overview(),
options = list(
searching = FALSE,
order = list(list(3, 'desc'))),
selection = "single")

})

row_index <- reactiveValues(index = 1)

observe({ # reset row_index when you manually select any row
row_index$index <- which(input$DT_show_docs_rows_selected == input$DT_show_docs_rows_all)
})

DT_show_docs_proxy <- dataTableProxy("DT_show_docs")

output$printScore <- renderText({
row <- input$DT_show_docs_rows_selected
text <- doc_overview()[row, "Filename"]
})

observeEvent(input$next_doc, {
# Function to select next row/document from datatable. When the button is clicked,
# and the first row is selected at this moment, I want to select/print the second
# row and so on.
req(input$DT_show_docs_rows_selected) # must select some row before using next_doc button
row_order <- input$DT_show_docs_rows_all # gives current order of rows
row_index$index <- isolate(row_index$index) + 1 # cycles throw the order one by one when you click next_button
selectRows(DT_show_docs_proxy, selected = row_order[row_index$index]) # selects the row of current index
})

output$test <- renderPrint({
input$DT_show_docs_rows_all # shows the order of rows in real time
})
}

# app
shinyApp(ui = ui, server = server)

R Shiny - Pre-selecting the row and page of a datatable inside a modalDialog

I guess this is what you're looking for. Your first problem was that you had to convert rv$selectedRow to numeric. Secondly it you were re-rendering your datatable everytime you pressed the "view" button. And thirdly you didn't do anything with your selectInput ("data").

I transformed rv$selectedRow to a numeric, moved your showModal to the ui and created an observer for your selectInput. In addition, I wrapped your datafarme in the datatable function, which I think is a bit more convenient.

Working example:

library(shiny)
library(DT)
library(shinyBS)

datasets = data.frame(cbind(id = seq_len(4), name = c('iris', 'mtcars', 'satellite', 'credit')))

# UI ----------------------------------------------------------------------
ui = fluidPage(

selectInput('data', 'Select dataset:', choices = datasets$id),

actionButton('view', 'View details'),
tags$head(tags$style("#df_popup .modal-footer{ display:none}
#df_popup .modal-header .close{display:none}")),
bsModal("df_popup", title='Available datasets', trigger='view',
tags$b('Click on a row to select a dataset.'),

br(),

br(),

DT::dataTableOutput('dfs'),

column(12, align='right',
modalButton('Cancel'),
bsButton('select', 'Select')
)
)
)

# SERVER ------------------------------------------------------------------
server <- shinyServer(function(input, output, session) {

rv = reactiveValues(selectedRow = NULL, selectedPage = NULL)

# Rendering the DT - pre-selection of row not working
output$dfs <- renderDT({
print(paste("selectedRow on 'renderDT':", rv$selectedRow))
datatable(datasets, options = list(
# displayStart = selectedPage,
pageLength = 2
),
filter = 'top',
selection = list(mode = 'single', selected=c(as.numeric(rv$selectedRow))),
rownames = F)
},
)

# Saving the selected row and updating the selectInput
observeEvent(input$select, {
rv$selectedRow = req(input$dfs_rows_selected)
print(paste("selectedRow on 'Select':", rv$selectedRow))
updateSelectInput(session = session, inputId = 'data', selected = datasets[rv$selectedRow, 1])
toggleModal(session, 'df_popup')
})

observeEvent(input$data, {
rv$selectedRow = input$data
print(paste("selectedRow on 'data':", rv$selectedRow))
})

})

shinyApp(ui, server)

Shiny with DT Select rows, keep cell color

You can define a CSS class for the background color (red below) and add it to the desired cells with a rowCallback. Then add this CSS:

.red {
background-color: #e34755;
}
table.dataTable tr.selected td.red {
background-color: #e34755 !important;
}

The app:

library(shiny)
library(DT)

rowCallback <- c(
"function(row, dat, displayNum, index){",
" if(dat[1] < 5){",
" $('td:eq(1)', row).addClass('red');",
" }",
"}"
)

css <- "
.red {
background-color: #e34755;
}
table.dataTable tr.selected td.red {
background-color: #e34755 !important;
}
"

ui <- fluidPage(

tags$head(
tags$style(HTML(css))
),

title = 'Select Table Rows',

fluidRow(
column(6, DTOutput('x1')),
column(6, plotOutput('x2', height = 500))
)
)

server <- function(input, output) {

output$x1 <- renderDT({
datatable(cars,
options = list(
columnDefs = list(list(targets = 3,visible = FALSE)),
rowCallback = JS(rowCallback)
)
)
})

# highlight selected rows in the scatterplot
output$x2 <- renderPlot({
s <- input$x1_rows_selected
par(mar = c(4, 4, 1, .1))
plot(cars[ ,-3])
if (length(s)) points(cars[s, , drop = FALSE], pch = 19, cex = 2)
})
}

shinyApp(ui, server)

Sample Image

R Shiny DataTable dynamic row selection with filtered data

Figured it out myself:
to get rid of the selected row dependancy I splitted the observer() into two observeEvent() functions, one for selected IDs and one for setting the filter on the selected IDs.

library(shiny)
library(DT)

options(shiny.reactlog=TRUE)

shinyApp(
ui = fluidPage(
tags$span(icon('toggle-off'), style = "display: none;") ,
tags$head(tags$style(".fa-toggle-off {color:#9b1f23}")),
tags$head(tags$style(".fa-toggle-on {color:#a2ad00}")),
selectizeInput("choose_grp","choose grp", choices = c("No Filter" = "", 1:20), multiple = T),
DT::dataTableOutput('x1'), verbatimTextOutput('x2'), verbatimTextOutput('x3')),

server = function(input, output, session) {

# a sample data frame
N <- 100
res = data.frame(
v1 = paste0('test', 1:N),
v2 = ifelse(!duplicated(rep(1:20,each = 5)), rep(1:20,each = 5), NA),
v2_grp = rep(1:20,each = 5),
r_g = rep('r', N),
r_g_grp = rep('r', N),
v3 = ifelse(!duplicated(rep(1:20,each = 5)),
as.character(icon('toggle-off')), NA),
ID = 1: N,
stringsAsFactors = FALSE
)

# reactive values to store selected rows
sel_all <- reactiveValues(all = data.frame(ID = res$ID, sel = rep(F,N)))
save_sel_vals <- reactiveValues(a = c(), d = c())

# observer selected rows/groups
observeEvent(input$x1_cell_clicked$row,{
res_old <- res
if (is.null(input$choose_grp)){
res <- res
} else if (any(input$choose_grp != "")){
res <- res[res$v2_grp %in% as.numeric(input$choose_grp),]
}

a_sel <- sel_all$all$sel[sel_all$all$ID %in% res$ID]

a <- data.frame(IDs = res$ID,
sel = a_sel)
if (is.null(input$x1_cell_clicked$row)) {
a[, 'sel'] <- F
} else if (isTRUE(a[input$x1_cell_clicked$row, 'sel'])){
a[input$x1_cell_clicked$row, 'sel'] <- F
} else if (!isTRUE(a[input$x1_cell_clicked$row, 'sel'])){
a[input$x1_cell_clicked$row, 'sel'] <- T
}

sel_all$all$sel[sel_all$all$ID %in% a$IDs] <- a$sel

isolate(a2 <- sel_all$all$sel[sel_all$all$ID %in% a$IDs])
isolate(d <- input$x1_cell_clicked$row -1)

save_sel_vals$a <- a2
save_sel_vals$d <- d
}, ignoreNULL = TRUE)

# observer IDs of filtered data
observeEvent(input$choose_grp, {
res_old <- res
if (is.null(input$choose_grp)){
res <- res
} else if (any(input$choose_grp != "")){
res <- res[res$v2_grp %in% as.numeric(input$choose_grp),]
}

a_sel <- sel_all$all$sel[sel_all$all$ID %in% res$ID]

a <- data.frame(IDs = res$ID,
sel = a_sel)

isolate(a2 <- sel_all$all$sel[sel_all$all$ID %in% a$IDs])
save_sel_vals$a <- a2

}, ignoreNULL = FALSE)

# render the table containing shiny inputs
output$x1 = DT::renderDataTable({

if (is.null(input$choose_grp)){
res <- res
} else if (any(input$choose_grp != "")){
res <- res[res$v2_grp %in% as.numeric(input$choose_grp),]
}

sel_rows <- save_sel_vals$a
res$r_g[sel_rows] <- 'g'
res$r_g_grp <- ifelse(res$v2_grp %in% res$v2_grp[sel_rows], 'g', 'r')
res$v3 <- ifelse(!is.na(res$v3), ifelse(
(res$v2_grp %in% res$v2_grp[sel_rows]), as.character(icon('toggle-on')), as.character(icon('toggle-off'))),
NA)

datatable(res, extensions = c('Scroller'), escape = F,
selection = list(mode = "multiple", target= 'row', selected = (1:nrow(res))[sel_rows]),
options = list(scrollX = T,
autoWidth = F,
deferRender = TRUE,
scrollY = 500,
scroller = T,
paging = T
), callback = JS(paste0('table.row(',save_sel_vals$d,').scrollTo(false);'))
) %>%
formatStyle(
columns = c("v3"), valueColumns = 'r_g_grp',
target = 'cell',
backgroundColor = styleEqual(c('r','g'), c('#e1a593','#d8dea8'))
)
} , server = F
)

# print the values of inputs
output$x2 = renderPrint({

data.frame(selected_row = input$x1_rows_selected,
selected_grp = res$v2_grp[input$x1_rows_selected]
)
})

output$x3 = renderPrint({
sel_all$all[1:10,]
})
}
)

Shiny DT::datatable - Change table content when lines are selected

You almost got it right! You have to put wrap your table with datatable:

output$mytable <- DT::renderDataTable(
datatable(cbind(mymtcars, v=rowSelect()),
options = list(dom = "t",ordering = FALSE),
selection = list(mode = "multiple",
selected =(1:5)[rowSelect()],
target = "row"))
)

Sample Image



Related Topics



Leave a reply



Submit