DT
DT copied to clipboard
the cell size changed when editing in DT
Hello I'm using shiny and DT to make a small app for my workmate. Here is the problem I meet.
I have a datatframe to show by DT, which contain some long str. These str should be editable. all the app work fine. But when I try to make some change in the str dataframe, I find something inconvenient. The origin cell was transformed into several line automatically. When I was editing, the "cell" or the "editable area" changed into only one line in a small "window". And I need to use "<" button to get to the star part of the string.
I doubt if there is any way to set the size of the "editable area", which could be as big as the origin cell size ?
Thanks a lot
https://community.rstudio.com/t/the-cell-size-changed-when-editing-in-dt/71675
By filing an issue to this repo, I promise that
-
[x] I have fully read the issue guide at https://yihui.name/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'm filing a bug report, I have included a minimal, self-contained, and reproducible example, and have also included
xfun::session_info('DT')
. I have upgraded all my packages to their latest versions (e.g., R, RStudio, and R packages), and also tried the development version:remotes::install_github('rstudio/DT')
. - 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.
That's normal, the editable area is a type=text
input, which has no support for multiline. Try this, this opens a textarea input for the edit:
library(shiny)
library(DT)
callback <- c(
"table.on('focus', 'input', function(){",
" $(this).on('blur', function(e){",
" e.stopImmediatePropagation();",
" return false;",
" })",
"});",
"$.contextMenu({",
" selector: '#dtable td input[type=text]',",
" trigger: 'hover',",
" autoHide: true,",
" items: {",
" text: {",
" name: 'Edit:',",
" type: 'textarea',",
" value: ''",
" },",
" sep1: '---------',",
" cancel: {",
" name: 'Cancel',",
" icon: function($element, key, item){",
" return 'context-menu-icon context-menu-icon-quit';",
" },",
" callback: function(itemKey, opts, e){",
" this.trigger('change');",
" $.contextMenu('destroy');",
" }",
" }",
" },",
" events: {",
" show: function(opts){",
" $.contextMenu.setInputValues(opts, {text: opts.$trigger.val()});",
" },",
" hide: function(opts){",
" var $this = this;",
" var data = $.contextMenu.getInputValues(opts, $this.data());",
" var $input = opts.$trigger;",
" $input.val(data.text);",
" $input.trigger('change');",
" }",
" }",
"});"
)
dat <- cbind(
iris[1:2,],
data.frame(
X = c(
"A very loooooooooooooooooooooooooooooooooooonnnnnnnnnggggggg string",
"xxx"
)
)
)
ui <- fluidPage(
tags$head(
tags$link(
rel = "stylesheet",
href = "https://cdnjs.cloudflare.com/ajax/libs/jquery-contextmenu/2.8.0/jquery.contextMenu.min.css"
),
tags$script(
src = "https://cdnjs.cloudflare.com/ajax/libs/jquery-contextmenu/2.8.0/jquery.contextMenu.min.js"
)
),
DTOutput("dtable")
)
server <- function(input, output){
output[["dtable"]] <- renderDT({
datatable(
dat, editable = "cell", callback = JS(callback)
)
})
}
shinyApp(ui, server)
@stla thank you so much for your suggestion I try your code and it works fine. but when i want get my datatable work as yours. something wrong happened. the "area didn't showed up. and here is my brief code
my_cb=c(.....what you show above.......)
ui <- pageWithSidebar(
mainPanel(
tags$head(
tags$link(
rel = "stylesheet",
href = "https://cdnjs.cloudflare.com/ajax/libs/jquery-contextmenu/2.8.0/jquery.contextMenu.min.css"
),
tags$script(
src = "https://cdnjs.cloudflare.com/ajax/libs/jquery-contextmenu/2.8.0/jquery.contextMenu.min.js"
)
),
DTOutput("comm_tmp"),
))
server <- function(input, output,session) {
output$comm_tmp<-renderDT({
datatable(x$comm,callback = JS(my_cb),editable = list(target = 'cell',disable = list(columns = c(1))),options = list(dom = 't'))
})
observeEvent(input$comm_tmp_cell_edit, {
x$comm[input$comm_tmp_cell_edit$row,input$comm_tmp_cell_edit$col] <<- input$comm_tmp_cell_edit$value
})
}
also here is another suestion: what if I want a little larger "area"? how could I set the "size"? thank you for your help
Hello @zhangjunjiang
You have to set the id of your table in the selector option:
" selector: '#comm_tmp td input[type=text]',"
To change the size of the textarea, click on its bottom right corner and drag.
Hello @zhangjunjiang
You have to set the id of your table in the selector option:
" selector: '#comm_tmp td input[type=text]',"
To change the size of the textarea, click on its bottom right corner and drag.
Thank you ,It works!!!!!
@zhangjunjiang
I've fixed an error in my code and I've improved it. With this code you can select the columns for which you request a textarea editing. For example here I select columns 5 and 6:
options = list(
columnDefs = list(
list(targets = c(5,6), className = "areaEdit")
)
)
To select all columns, set targets = "_all"
.
Moreover you don't need to set the table id in the JS code. In this way you can use the same callback
for multiple tables.
library(shiny)
library(DT)
callback <- c(
"table.on('focus', 'td.areaEdit input[type=text]', function(){",
" $(this).on('blur', function(e){",
" e.stopImmediatePropagation();",
" return false;",
" })",
"});",
"var id = $(table.table().node()).closest('.datatables').attr('id');",
"$.contextMenu({",
" selector: '#' + id + ' td.areaEdit input[type=text]',",
" trigger: 'hover',",
" autoHide: true,",
" items: {",
" text: {",
" name: 'Edit:',",
" type: 'textarea',",
" value: ''",
" },",
" sep1: '---------',",
" cancel: {",
" name: 'Cancel',",
" icon: function($element, key, item){",
" return 'context-menu-icon context-menu-icon-quit';",
" },",
" callback: function(itemKey, opts, e){",
" this.trigger('change');",
" }",
" }",
" },",
" events: {",
" show: function(opts){",
" $.contextMenu.setInputValues(opts, {text: opts.$trigger.val()});",
" },",
" hide: function(opts){",
" var $this = this;",
" var data = $.contextMenu.getInputValues(opts, $this.data());",
" var $input = opts.$trigger;",
" $input.val(data.text);",
" $input.trigger('change');",
" }",
" }",
"});"
)
dat <- cbind(
iris[1:2,],
data.frame(
X = c(
"A very loooooooooooooooooooooooooooooooooooonnnnnnnnnggggggg string",
"xxx"
)
)
)
ui <- fluidPage(
tags$head(
tags$link(
rel = "stylesheet",
href = "https://cdnjs.cloudflare.com/ajax/libs/jquery-contextmenu/2.8.0/jquery.contextMenu.min.css"
),
tags$script(
src = "https://cdnjs.cloudflare.com/ajax/libs/jquery-contextmenu/2.8.0/jquery.contextMenu.min.js"
)
),
DTOutput("dtable")
)
server <- function(input, output){
output[["dtable"]] <- renderDT({
datatable(
dat, editable = "cell", callback = JS(callback),
options = list(
columnDefs = list(
list(targets = c(5,6), className = "areaEdit")
)
)
)
})
}
shinyApp(ui, server)
@stla Thank you :)