Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

extended editor capabilities #509

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open

Conversation

LukasK13
Copy link

I extended the editor capabilities, so distinct columns can be marked as editable and the type of the editor can be switched between a text input and a select input.
The editor is enabled by using editable = TRUE option for the data tables init. The additional attributes editType and editAttribs define the type of the editor and the editor attributes. They are set up as follows:

      editType = list("1" = "text", "2" = "text", "3" = "text", "4" = "text", "5" = "select"),
      editAttribs = list("1" = list(placeholder = "Length"), "2" = list(placeholder = "Width"),
                         "3" = list(placeholder = "Length"), "4" = list(placeholder = "Width"),
                         "5" = list(options = c("setosa", "versicolor", "virginica")))
    )

The names in the list specify the target column, "text" specifies a text input and "select" specifies a select input. Currently, the only available option for a text input is the placeholder and for a select input the selectable options.

Furthermore the editor now offers reactivity to the keys enter, escape and tab.

Hopefully, this commit fixes #493

For testing is used the following code:

library(shiny)
library(DT)
shinyApp(
  ui = fluidPage(
    title = 'Double-click to edit table cells',
    titlePanel('Double-click to edit table cells'),
    DTOutput('x1')
  ),
  server = function(input, output, session) {
    d1 = iris

    output$x1 = renderDT(d1, selection = 'none', options = list(editable = T,
      editType = list("1" = "text", "2" = "text", "3" = "text", "4" = "text", "5" = "select"),
      editAttribs = list("1" = list(placeholder = "Length"), "2" = list(placeholder = "Width"),
                         "3" = list(placeholder = "Length"), "4" = list(placeholder = "Width"),
                         "5" = list(options = c("setosa", "versicolor", "virginica")))
    ))

    proxy1 = dataTableProxy('x1')

    observeEvent(input$x1_cell_edit, {
      info = input$x1_cell_edit
      str(info)
      i = info$row
      j = info$col
      v = info$value
      d1[i, j] <<- DT::coerceValue(v, d1[i, j])
      replaceData(proxy1, d1, resetPaging = FALSE)
    })
  }
)

PS: Please excuse my bad javascript, I'm both new to GitHub and javascript.

I extendedn the editor capabilities, so distinct columns can be marked as editable and the type of the editor can be switched between a textinput and a selectinput.
Copy link
Member

@yihui yihui left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks pretty cool, but I don't have time to review it by myself (until perhaps 6 months later). Thanks anyway!

What do you think? @shrektan

@LukasK13
Copy link
Author

I updated my commit so the previous enabling of the editor will work. Additionally targeting the editor column is now independent from the visibility of the row names. The code for testing changed as follows:

library(shiny)
library(DT)
shinyApp(
  ui = fluidPage(
    title = 'Double-click to edit table cells',
    titlePanel('Double-click to edit table cells'),
    DTOutput('x1')
  ),
  server = function(input, output, session) {
    d1 = iris

    output$x1 = renderDT(d1, selection = 'none', editable = T, rownames = T, options = list(
      editType = list("0" = "text", "1" = "text", "2" = "text", "3" = "text", "4" = "select"),
      editAttribs = list("0" = list(placeholder = "Length"), "1" = list(placeholder = "Width"),
                         "2" = list(placeholder = "Length"), "3" = list(placeholder = "Width"),
                         "4" = list(options = c("setosa", "versicolor", "virginica")))
    ))

    proxy1 = dataTableProxy('x1')

    observeEvent(input$x1_cell_edit, {
      info = input$x1_cell_edit
      str(info)
      i = info$row
      j = info$col
      v = info$value
      d1[i, j] <<- DT::coerceValue(v, d1[i, j])
      replaceData(proxy1, d1, resetPaging = FALSE)  # important
    })
  }
)

@shrektan
Copy link
Collaborator

It looks like a great patch, thanks, @LukasK13. I'll try to find time to review it tomorrow.

@LukasK13
Copy link
Author

Awesome. We should think about discarding changes made in the editor when the input loses focus. I think discading the changes may slow down the workflow, but would increase the security of not changing any values by accident but only by pressing tab or enter.

@shrektan
Copy link
Collaborator

shrektan commented Feb 25, 2018

@LukasK13 Thanks again, I think the example's effect looks very nice, especially the dropdown box to select inputs.

As you said, in the long term, we want the workflow is smooth, effective and safe. So it's good to make this patch fits the future. Since DT is a popular package and this patch basically defines the future editing interface of DT, I need more time to think about it.

Some random thinking so far

In my limited experience, I guess the editing feature is most useful when designing an CRUD interface, as discussed here. Considering this, without thinking too much about the implementation difficulties, these features will be nice:

  • Works for both client mode and server side processing.
  • Different input mode for different field type, by default: Date -> a calendar selector, factor -> a dropdown, etc.
  • Input validations:
    • check the input types by default?
    • customised validation rules?
    • how to inform the user? pop up an error msg box?
  • Add / Delete a row easily: trigered by right-click on an row?
  • Be able to control which parts of the table is editable
  • Make the readonly / editing state explicitly: the user is either viewing the table or editing it. In the editing state, the user is aware of it clearly because the selected cell gets highlighted in a distinct color (an idea...). It's also ideal to have a button to switch the state.
  • Excel-like editing experience (my personal taste and we may learn some from rhandsontable ): The user can move around the selected cell via the arrow keys. The user can edit the cell by inputing text directly, pressing Enter or simply Mousedown.

@LukasK13
Copy link
Author

That sounds amazing.
I think that would be the right direction to go to.
Probably we should start by designing a method for initializing the editor with respect to the future additions. Then we can start by adding small features from time to time. I think using text input and select input is good for a start.
Did you ever evaluate the editor by data tables?

@shrektan
Copy link
Collaborator

shrektan commented Mar 4, 2018

@LukasK13 No I've never evaluated the editor of datatables but I do like its examples:

It would be good if the editing experience here is similar to the inline-editing of the editor of datatables. What do you think?

@LukasK13
Copy link
Author

LukasK13 commented Mar 5, 2018

@shrektan The inline-editing of the editor is awesome. However I wanted to be able to select rows for deletion for example. Unfortunately it isn't possible for me to include the selection checkboxes easily in DT. That's the reason why sticked to the activation of the editor by double clicking on a cell.
I would rather stick to only enable editing of available cells and leave the integration of adding and removing rows to the user.

@shrektan
Copy link
Collaborator

shrektan commented Mar 6, 2018

@LukasK13 Yes, I think your current PR is good enough. However, I'm extremely busy recently. 😢 I will take a closer look as soon as I can.

@LukasK13
Copy link
Author

LukasK13 commented Mar 6, 2018

@shrektan Ok no need to hurry, I'll see if I'll find the time to implement a date picker and the automatic detection of the input type. I would recommend using a checkbox for deletion like shown in https://datatables.net/extensions/select/examples/initialisation/checkbox.html . This would enable us activating the editor on a single click and not on a double click.

@LukasK13
Copy link
Author

Hey @shrektan
I experimented with the automatic detection of the column types and was successful for text input, number input and select input. The implementation of the datetimepicker however has turned out to be problematic. I tried to use the input type datetime-local (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/datetime-local), but this input field is not widely supported. Therefore I tried to implement a bootstrap datetime picker (https://eonasdan.github.io/bootstrap-datetimepicker/) which wasn't successful too.
The implementation of a button to add a new row to the table wasn't successful either, as it will become pretty messy creating and evaluating the corresponding modal dialog.
Do you think there is any option to use the data tables editor or somehow copy it (without violating the copy right)?

@shrektan
Copy link
Collaborator

shrektan commented Mar 27, 2018

@LukasK13 Being busy for a while... Well, yes, the editor of datatable looks good for me but I can't see a way of using if for free... Moreover, the JS code in the trial version I downloaded gets obfuscated so we may not be able to borrow the ideas. In addition, the size scripts is about 200KB, which means it must be quite complicated to implement the full feature...

I'll see if any other way to make the editing experience closer to the official editor based on your code in the weekend.

@shrektan shrektan mentioned this pull request Mar 27, 2018
6 tasks
@jienagu
Copy link

jienagu commented Feb 4, 2019

Hi @LukasK13 @shrektan @yihui ,

Here is the DT editor I built that has has (almost) all features of data table editor. Here is a live shiny app demo (limited active hours): https://appforiarteam.shinyapps.io/DT_Editor_Example2/ Github code: https://github.com/jienagu/DT-Editor

Let me know if this is what you all are looking for. Some features are based on Shiny such as showModal().

It supports multiple data formats (numeric, character, and date). If you want to integrate the editor features into DT package, just "parameterized" the data input part to any data (line 52-64 of server.r).

dt_editor

Welcome to discuss and let me know if you have any questions.

@jienagu
Copy link

jienagu commented Apr 1, 2019

Followed up with my last comment, I already parameterized the data input part using shiny modules. Repo: https://github.com/jienagu/DT_editor_shiny_module

  • This app utilize shiny module that can fit for any data.table. You just need to create your data.table and load it to the same location of your shiny app as note.rds

  • Currently, I am working on an elegant way to handle Date format so please convert any date col to character/factor before you load the data.table to this app.

Hopefully it is helpful.

@yihui
Copy link
Member

yihui commented Apr 4, 2019

Finally I got some time to work on this and borrowed some of @LukasK13's great ideas (many thanks!). Please see my comment at #493 (comment).

I like the select input implemented in @LukasK13's PR, but ran out of time (still have tons of other things to do). I'll revisit it in the future. The main thing I was thinking was that the options could be automatically passed to the JS side like I did for the column filters:

DT/R/datatables.R

Lines 455 to 458 in 0d1b8de

tags$select(
multiple = 'multiple', style = 'width: 100%;',
`data-options` = native_encode(jsonlite::toJSON(as.character(d)))
),

Thanks again everyone for the very helpful input and contribution!

@lsusatyo-gcmlp
Copy link

I updated my commit so the previous enabling of the editor will work. Additionally targeting the editor column is now independent from the visibility of the row names. The code for testing changed as follows:

library(shiny)
library(DT)
shinyApp(
  ui = fluidPage(
    title = 'Double-click to edit table cells',
    titlePanel('Double-click to edit table cells'),
    DTOutput('x1')
  ),
  server = function(input, output, session) {
    d1 = iris

    output$x1 = renderDT(d1, selection = 'none', editable = T, rownames = T, options = list(
      editType = list("0" = "text", "1" = "text", "2" = "text", "3" = "text", "4" = "select"),
      editAttribs = list("0" = list(placeholder = "Length"), "1" = list(placeholder = "Width"),
                         "2" = list(placeholder = "Length"), "3" = list(placeholder = "Width"),
                         "4" = list(options = c("setosa", "versicolor", "virginica")))
    ))

    proxy1 = dataTableProxy('x1')

    observeEvent(input$x1_cell_edit, {
      info = input$x1_cell_edit
      str(info)
      i = info$row
      j = info$col
      v = info$value
      d1[i, j] <<- DT::coerceValue(v, d1[i, j])
      replaceData(proxy1, d1, resetPaging = FALSE)  # important
    })
  }
)

Has this feature implemented yet? I had retrieve the latest but wasn't able to find it. Thank you.

@yihui
Copy link
Member

yihui commented May 31, 2019

@lsusatyo-gcmlp If you mean select inputs in the table, no. Currently only text inputs are supported.

@Sumeda1985
Copy link

I am just wondering if there is a way to edit data table from a drop down list for factor variables ?

@LukasK13
Copy link
Author

This should be possible using my fork and the code examples above. However, this PR hasn't been merged yet, as my code is pretty ugly;)

@emillykkejensen
Copy link

Any ETA on when this will be merged into master? @shrektan

@corwinjoy
Copy link

This fix sounds great! Can't wait to see it! My current drop-down workaround on the client side for DT is a real headache.

@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@stla
Copy link
Collaborator

stla commented Nov 8, 2023

@shrektan

Excel-like editing experience (my personal taste and we may learn some from rhandsontable ): The user can move around the selected cell via the arrow keys. The user can edit the cell by inputing text directly, pressing Enter or simply Mousedown.

I did it: https://laustep.github.io/stlahblog/posts/DTcallbacks.html.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Improve edit functionality
10 participants