我想限制数据表中列和行的可编辑模式。 目前,在这个最小的示例中,我只能编辑特定列,但它不适用于限制行(不允许行 1 到 5)。
有人有想法吗?
谢谢您的提前
library(shiny)
library(DT)
shinyApp(
ui = fluidPage(DTOutput('tbl')),
server = function(input, output) {
output$tbl = renderDT(
datatable(data = iris,
options = list(lengthChange = FALSE),
editable = list(target = 'column', disable = list(columns = c(1:3), rows = c(1:5))))
)
}
)
您可以从我提供的链接中调整代码,如下所示。
library(shiny)
library(DT)
disabled_rows = paste0("'", paste0("row", c(1,2,3)), "'") ### disabled rows are listed here
rowCallback <- c(
"function(row, data, displayNum, displayIndex){",
sprintf(" var indices = [%s];", toString(disabled_rows)),
" if(indices.indexOf($(row).attr('id')) > - 1){",
" $(row).find('td').addClass('notselectable').css({'background-color': '#eee', 'color': '#bbb'});",
" }",
"}"
)
get_selected_rows <- c(
"var id = $(table.table().node()).closest('.datatables').attr('id');",
"table.on('click', 'tbody', function(){",
" setTimeout(function(){",
" var indexes = table.rows({selected:true}).indexes();",
" var indices = Array(indexes.length);",
" for(var i = 0; i < indices.length; ++i){",
" indices[i] = indexes[i];",
" }",
" Shiny.setInputValue(id + '_rows_selected', indices);",
" }, 0);",
"});"
)
drag_selection <- c(
"var dt = table.table().node();",
"$(dt).selectable({",
" distance : 10,",
" selecting: function(evt, ui){",
" $(this).find('tbody tr').each(function(i){",
" if($(this).hasClass('ui-selecting')){",
" table.row(i).select();",
" }",
" });",
" }",
"}).on('dblclick', function(){table.rows().deselect();});"
)
dat <- iris
dat$ID <- paste0("row", 1:nrow(iris))
rowNames <- TRUE
colIndex <- as.integer(rowNames)
shinyApp(
ui = fluidPage(DTOutput('tbl')),
server = function(input, output, session) {
### disable selected rows only
# output$tbl <- renderDT({
#
# datatable(
# dat,
# rownames = rowNames,
# callback = JS(get_selected_rows),
# class = 'hover row-border order-column',
# options = list(
# rowId = JS(sprintf("function(data){return data[%d];}",
# ncol(dat)-1+colIndex)),
# rowCallback = JS(rowCallback),
# select = list(style = "multi", selector = "td:not(.notselectable)")
# ),
# extensions = "Select", selection = 'none'
# )
# }, server = TRUE)
### disable selected rows and columns
output$tbl <- renderDT({
datatable(
dat,
rownames = rowNames,
callback = JS(get_selected_rows),
class = 'hover row-border order-column',
options = list(
lengthChange = FALSE,
rowId = JS(sprintf("function(data){return data[%d];}",
ncol(dat)-1+colIndex)),
rowCallback = JS(rowCallback),
select = list(style = "multi", selector = "td:not(.notselectable)")
),
extensions = "Select",
editable = list(target = 'column', disable = list(columns = c(2:3) )), selection = 'none',
)
}, server = TRUE)
### disable selected columns only
# output$tbl = renderDT(
# datatable(data = iris,
# options = list(lengthChange = FALSE),
# #extensions = "Select", selection = 'none',
# editable = list(target = 'column', disable = list( columns = c(2:3) )) )
# )
}
)
解决方法:
通过忽略代理中的更改来避免修改
library(shiny)
library(DT)
forbidden_rows <- 1
disabled_rows <- paste0("'", paste0("row", forbidden_rows), "'") ### disabled rows are listed here
rowCallback <- c(
"function(row, data, displayNum, displayIndex){",
sprintf(" var indices = [%s];", toString(disabled_rows)),
" if(indices.indexOf($(row).attr('id')) > - 1){",
" $(row).find('td').addClass('non-modifiable').css({'background-color': '#eee', 'color': '#bbb'});",
" }",
"}"
)
rownames_bool <- T
colIndexfix <- as.integer(rownames_bool)
shinyApp(
ui = fluidPage(
DTOutput("x1")
),
server = function(input, output, session) {
x <- iris
x$ID <- paste0("row", 1:nrow(iris))
y <- reactiveVal(x)
output$x1 <- renderDT({
datatable(x,
selection = "none",
editable = list(
target = "column",
disable = list(
columns = 0:1,
# non functional!, just, desired https://github.com/rstudio/DT/issues/1118
rows = 1
)
),
options(list(
rowId = JS(sprintf(
"function(data){return data[%d];}",
ncol(dat) - 1 + colIndexfix
)),
rowCallback = JS(rowCallback)
)),
rownames = rownames_bool
)
})
proxy <- dataTableProxy("x1")
observeEvent(input$x1_cell_edit, {
info <- input$x1_cell_edit
if (rownames_bool) {
len <- length(info$row)
i <- info$row[2:len]
j <- info$col[2:len]
v <- info$value[2:len]
}
x <- y()
for (k in seq_along(i)) {
if (i[k] %in% forbidden_rows) {
next
}
current_class <- class(x[[j[k]]])[1]
coerced_value <- switch(current_class,
numeric = as.numeric(v[k]),
integer = as.integer(v[k]),
character = as.character(v[k]),
logical = as.logical(v[k]),
factor = factor(v[k], levels = levels(x[[j[k]]])),
v[k]
)
x[i[k], j[k]] <- coerced_value
}
y(x)
replaceData(proxy, x, resetPaging = FALSE, rownames = rownames_bool) # important
})
}
)