DT
DT copied to clipboard
How to select the entire row, while having only first(one) column clickable?
I need to do the same as here:
https://editor.datatables.net/examples/inline-editing/simple.html
Ideally with a checkbox.
With the select extension, this is configured simply: select = list(style = 'multi+shift', selector = "td:first-child"),
Only via the built-in selectable that works with the server-side on the R (Shiny)...
I need to make only the cells of the first non-editable column selectable, because selectable and editable are not very conveniently combined together in one cell
P.S.: My SO question: https://stackoverflow.com/questions/76473946/how-to-select-the-entire-row-while-having-only-firstone-column-clickable
By filing an issue to this repo, I promise that
- [x] I have fully read the issue guide at https://yihui.org/issue/.
- [x] I have provided the necessary information about my issue.
- If I'm asking a question, I have already asked it on Stack Overflow or RStudio Community, waited for at least 24 hours, and included a link to my question there.
- If I have posted the same issue elsewhere, I have also mentioned it in this issue.
- [x] I have learned the Github Markdown syntax, and formatted my issue correctly.
I understand that my issue may be closed if I don't fulfill my promises.
In Shiny?
Yes
Hmm I thought I had a solution but there's a problem. Try the app below. When you click on a checkbox, the row is selected as expected. The problem is that if you click elsewhere in the table, this unselects the selected rows.
Any idea, @yihui ?
library(shiny)
library(DT)
checkboxColumn <- function(len, ...) {
inputs <- character(len)
for(i in seq_len(len)) {
inputs[i] <- as.character(
checkboxInput(paste0("checkb_", i), label = NULL, ...)
)
}
inputs
}
dat <- data.frame(
checkme = checkboxColumn(4),
fruit = c("apple", "cherry", "pineapple", "pear"),
letter = c("a", "b", "c", "d")
)
callback <- c(
sprintf("var selected = [%s];", toString(rep("false", 4))),
"$('body').on('click', '[id^=checkb]', function(){",
" var id = this.getAttribute('id');",
" var i = parseInt(/checkb_(\\d+)/.exec(id)[1]);",
" var value = $(this).prop('checked');",
" selected[i-1] = value; console.log(selected);",
" Shiny.setInputValue('selected', selected);",
"})"
)
ui <- fluidPage(
br(),
DTOutput("dtable")
)
server <- function(input, output, session) {
output[["dtable"]] <- renderDT({
datatable(
dat,
escape = FALSE,
selection = list(
mode = "multiple", selected = NULL, target = "row", selectable = FALSE
),
callback = JS(callback)
)
})
proxy <- dataTableProxy("dtable")
observeEvent(input[["selected"]], {
selected <- which(as.logical(input[["selected"]]))
print(selected)
selectRows(proxy, selected, ignore.selectable = TRUE)
})
}
shinyApp(ui, server)
Ok, I found a solution. There is some flickering but it works.
library(shiny)
library(DT)
checkboxColumn <- function(len, ...) {
inputs <- character(len)
for(i in seq_len(len)) {
inputs[i] <- as.character(
checkboxInput(paste0("checkb_", i), label = NULL, ...)
)
}
inputs
}
dat <- data.frame(
checkme = checkboxColumn(4),
fruit = c("apple", "cherry", "pineapple", "pear"),
letter = c("a", "b", "c", "d")
)
callback <- c(
sprintf("var selected = [%s];", toString(rep("false", 4))),
"$('body').on('click', '[id^=checkb]', function() {",
" var id = this.getAttribute('id');",
" var i = parseInt(/checkb_(\\d+)/.exec(id)[1]);",
" var value = $(this).prop('checked');",
" selected[i-1] = value;",
" Shiny.setInputValue('selected', selected);",
"});",
"table.on('click', 'tr', function() {",
" Shiny.setInputValue('selected', selected, {priority: 'event'});",
"});"
)
ui <- fluidPage(
br(),
DTOutput("dtable")
)
server <- function(input, output, session) {
output[["dtable"]] <- renderDT({
datatable(
dat,
rownames = FALSE,
escape = FALSE,
selection = list(
mode = "multiple", selected = NULL, target = "row", selectable = FALSE
),
callback = JS(callback)
)
})
proxy <- dataTableProxy("dtable")
observeEvent(input[["selected"]], {
selected <- which(as.logical(input[["selected"]]))
selectRows(proxy, selected, ignore.selectable = TRUE)
})
}
shinyApp(ui, server)
Interesting, I'll try!
The line of code is a bit "tension" me: sprintf("var selected = [%s];", toString(rep("false", 4)))
The table rows will be filled in/deleted in the process, and I only change the content using DT::editData
, and not rebuild the UI entirely