将selection 设置为"none";我们将在Select 扩展和回调的帮助下“手动”定义选择行为。启用此扩展,使用选项 select = "api",并将类 notselectable 分配给第 12 和 13 列(“选择”和“操作”):
datatable(mtcars, escape=FALSE, callback = JS(callback),
extensions = "Select", selection = "none",
options = list(
scrollX = TRUE,
pageLength = 5,
columnDefs = list(
list(className = "notselectable", targets = c(12,13))
),
select = "api"))
现在回调:
callback <- c(
"table.on('click', 'tbody td', function(){",
" // if the column is already selected, deselect it:",
" if(table.column(this, {selected: true}).length){",
" table.column(this).deselect();",
" // otherwise, select the column unless there's the class 'notselectable':",
" } else if(!$(this).hasClass('notselectable')){",
" table.column(this).select();",
" }",
"});"
)
编辑
评论中提出的新问题:
真实应用程序中的表格是反应式的,可以添加新列,因此
目标 = c(12,13) 将停止显示表格。我怎样才能
将最后两列定义为不可选择而不是
具体列号?
使用这个回调:
callback <- c(
"var ncols = table.columns().count();",
"table.on('click', 'tbody td', function(){",
" // if the column is selected, deselect it:",
" if(table.column(this, {selected: true}).length){",
" table.column(this).deselect();",
" // otherwise, select the column unless it's among the last two columns:",
" } else if([ncols-1, ncols-2].indexOf(table.column(this).index()) === -1){",
" table.column(this).select();",
" }",
"});"
)
并且不需要为最后两列设置一个类:
datatable(mtcars, escape=FALSE, callback = JS(callback),
extensions = "Select", selection = "none",
options = list(
scrollX = TRUE,
pageLength = 5,
select = "api"))
编辑 2
在 Shiny 中获取所选列的索引:
callback <- c(
"var ncols = table.columns().count();",
"var tbl = table.table().node();",
"var tblID = $(tbl).closest('.datatables').attr('id');",
"table.on('click', 'tbody td', function(){",
" // if the column is selected, deselect it:",
" if(table.column(this, {selected: true}).length){",
" table.column(this).deselect();",
" // otherwise, select the column unless it's among the last two columns:",
" } else if([ncols-1, ncols-2].indexOf(table.column(this).index()) === -1){",
" table.column(this).select();",
" }",
" // send selected columns to Shiny",
" var indexes = table.columns({selected:true}).indexes();",
" var indices = Array(indexes.length);",
" for(var i = 0; i < indices.length; ++i){",
" indices[i] = indexes[i];",
" }",
" Shiny.setInputValue(tblID + '_columns_selected', indices);",
"});"
)
那么选中列的索引在input$endotable_columns_selected如果表中有行名;如果没有行名,则索引为input$endotable_columns_selected + 1。
编辑 3
这是删除行的更简洁的方法:
callback <- c(
"var ncols = table.columns().count();",
"var tbl = table.table().node();",
"var tblID = $(tbl).closest('.datatables').attr('id');",
"table.on('click', 'tbody td', function(){",
" // if the column is selected, deselect it:",
" if(table.column(this, {selected: true}).length){",
" table.column(this).deselect();",
" // otherwise, select the column unless it's among the last two columns:",
" } else if([ncols-2, ncols-3].indexOf(table.column(this).index()) === -1){",
" table.column(this).select();",
" }",
" // send selected columns to Shiny",
" var indexes = table.columns({selected:true}).indexes();",
" var indices = Array(indexes.length);",
" for(var i = 0; i < indices.length; ++i){",
" indices[i] = indexes[i];",
" }",
" Shiny.setInputValue(tblID + '_columns_selected', indices);",
"});",
"/* ---------------------------------------------------------- */",
"// Handler to delete rows",
"Shiny.addCustomMessageHandler('deleteHandler', function(rowIDs){",
" for(var i = 0; i < rowIDs.length; ++i){",
" deleteRow(rowIDs[i]);",
" }",
"});"
)
js <- paste0(
c(
"function deleteRow(rowID){",
" var table = $('#endotable').find('table').DataTable();",
" var nrows = table.rows().count();",
" for(var i=0; i < nrows; ++i){",
" if(table.row(i).id() == rowID){",
" table.row(i).remove().draw(false);",
" break;",
" }",
" }",
"}"
),
collapse = "\n"
)
ui <- fluidPage(
tags$head(tags$script(HTML(js))),
h3(strong("My picker"),align="center"),
hr(),
HTML('<div class="btn-group" role="group" aria-label="Basic example">'),
actionButton(inputId = "Del_row_head",label = "Delete selected rows"),
HTML('</div>'),
tags$script(HTML('$(document).on("click", "input", function () {
var checkboxes = document.getElementsByName("row_selected");
var checkboxesChecked = [];
for (var i=0; i<checkboxes.length; i++) {
if (checkboxes[i].checked) {
checkboxesChecked.push(checkboxes[i].value);
}
}
Shiny.onInputChange("checked_rows",checkboxesChecked);
})')),
# tags$script("$(document).on('click', '#Main_table button', function () {
# Shiny.onInputChange('lastClickId',this.id);
# Shiny.onInputChange('lastClick', Math.random())
# });"),
dashboardPage(
dashboardHeader(title = 'My shiny'),
dashboardSidebar(),
dashboardBody( DT::dataTableOutput("endotable")))
)
mtcars[["Select"]] <-
paste0('<input type="checkbox" name="row_selected" value="row_',1:nrow(mtcars),'"><br>')
mtcars[["Actions"]] <-
paste0('
<div class="btn-group" role="group" aria-label="Basic example">
<button type="button" class="btn btn-secondary delete" id=delete_',1:nrow(mtcars),'>Delete</button>
</div>
')
mtcars[["ROWID"]] <- paste0("row_", 1:nrow(mtcars))
server <- function(input, output, session) {
RV <- reactiveValues(data = mtcars)
# observe({
# print(input$endotable_columns_selected)
# })
output$endotable = DT::renderDT({
datatable(RV$data, escape=FALSE, callback = JS(callback),
extensions = "Select", selection = "none",
options = list(
scrollX = TRUE,
pageLength = 5,
select = "api",
rowId = JS(sprintf("function(data){return data[%d];}", ncol(RV$data))),
columnDefs = list(
list(visible = FALSE, targets = -1)
)
)
)
}, server = FALSE)
observeEvent(input[["Del_row_head"]], {
session$sendCustomMessage("deleteHandler", as.list(input$checked_rows))
})
# observeEvent(input$Del_row_head,{
# row_to_del <- as.numeric(gsub("Row","",input$checked_rows))
# RV$data <- RV$data[-row_to_del, ]
# })
#
# observeEvent(input$lastClick,
# {
# if (input$lastClickId%like%"delete")
# {
# row_to_del=as.numeric(gsub("delete_","",input$lastClickId))
# RV$data=RV$data[-row_to_del]
# }
# else if (input$lastClickId%like%"modify")
# {
# showModal(modal_modify)
# }
# }
# )
}
shinyApp(ui = ui, server = server)