'Shiny datatable mode editable - restrict specific columns AND ROWS

I would like to restrict editable mode in datatable for columns and rows. For the moment, in this minimal example, I can edit only specific columns but it doesn't work for restrict rows (not allow rows 1 to 5).

Does anyone have an idea?

Thank you for advance

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))))
    )
  }
)


Solution 1:[1]

You can adapt the code from the link I provided as shown below.

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) )) )
    # )
  }
)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 YBS