handsontable / handsontable

JavaScript data grid with a spreadsheet look & feel. Works with React, Angular, and Vue. Supported by the Handsontable team ⚡
https://handsontable.com
Other
19.73k stars 3.03k forks source link

Javascript Date objects breaking datepicker cells #4291

Open jongunter opened 7 years ago

jongunter commented 7 years ago

Description

If my data source has JavaScript Date objects in certain fields, they do not render/edit correctly in the Handsontable. I experience the following issues:

If this is user error, the Documentation doesn't seem to explain what I'm doing wrong.

Steps to reproduce

  1. Create a Handsontable with the following settings
    let settings = {
            data: [
                {
                    name: 'Hello',
                    date: new Date(),
                },
                {
                    name: 'World',
                    date: new Date()
                }
            ],
            columns: [
                {
                    data: 'name',
                },
                {
                    data: 'date',
                    type: 'date',
                    dateFormat: 'MM/DD/YY',
                    correctFormat: true
                }
            ]
        }
  2. Notice the date cells are not formatted properly.
  3. Edit one of the "name" cells. They should work just fine.
  4. Edit one of the "date" cells. It will become "stuck" as the selected cell and you cannot edit anything else until you refresh the page. There are no errors in the console.

Demo

Coming soon, but the repro steps above should be enough to reproduce the issue.

Your environment

sherdeadlock commented 7 years ago

date should be a string, '06/11/17'

jongunter commented 7 years ago

That's what I feared. It certainly seems odd that HandsOnTable can only handles dates stored as a string when JavaScript has a built-in Date type, especially when interacting with data from other components/frameworks that have dates stored native Dates.

I guess my only solution is to wrap my data in an adapter class that converts the dates to strings for HandsOnTable to manipulate? Or maybe hook into a change event and convert dates between Dates and Strings on-the-fly?

jongunter commented 7 years ago

Furthermore, I think the documentation for the date cell type should be clarified so developers know that date picker cell values should be strings: https://docs.handsontable.com/pro/1.11.0/demo-date.html

jongunter commented 7 years ago

I'm trying to extend the built-in datepicker, so it converts to/from dates and strings. I have this code, but the dates still seem to be saving as strings. Does anyone have any ideas on how to make this work?

var originalDateEditor = Handsontable.editors.DateEditor.prototype;
var DateEditor = originalDateEditor.extend();
DateEditor.prototype.prepare = function(row, col, prop, td, originalValue, cellProperties){
    if(originalValue){
        arguments[4] = moment(originalValue).format('DD/MM/YYYY');
    }
    return originalDateEditor.prepare.apply(this, arguments);
};

DateEditor.prototype.getValue = function(){
    var stringDate = originalDateEditor.getValue.apply(this, arguments);
    return new Date(stringDate);
}

Handsontable.editors.registerEditor('myDate', DateEditor);
jongunter commented 7 years ago

It seems my custom editor code is fine. The real problem is that populateFromArray() (called internally after edits) seems to be converting my Date objects to strings. setDataAtCell() does not seem to do this.

If I call this to change the value of row2, col0, my value becomes a string:

hotInstance.populateFromArray(2, 0, [[new Date()]], 2, 0, 'edit');
jongunter commented 7 years ago

This is my workaround that seems to work okay. It obviously has lots of limitations (editing multiple cells), but it does the job for now. In the long term, the ability to able to handle native Date objects in HandsOnTable would be a much-appreciated feature.

var originalDateEditor = Handsontable.editors.DateEditor.prototype;
var DateEditor = originalDateEditor.extend();
DateEditor.prototype.prepare = function(row, col, prop, td, originalValue, cellProperties){
    if(originalValue){
        arguments[4] = moment(originalValue).format('DD/MM/YYYY');
    }
    return originalDateEditor.prepare.apply(this, arguments);
};

DateEditor.prototype.saveValue = function(value){
   var stringDate = value[0][0];
            var momentDate = moment(stringDate, DATE_FORMAT);
            var date;
            if (momentDate.isValid()) {
                date = momentDate.toDate();
            } else {
                date = null;
            }

            this.instance.setDataAtCell(this.row, this.col, date, 'edit');
}
Handsontable.editors.registerEditor('myDate', DateEditor);

In addition to this code, I would probably add a custom renderer to my cell that displays the date in a more user-friendly format.

AMBudnik commented 7 years ago

Hi @jongunter

currently, we are using Datapicker and momemnt.js to handle date cell types so we have some limitations. We will be switching to custom code however it is a plan for further future.

ps. here https://jsfiddle.net/handsoncode/s02sbtww is an example from out blog post called 'Getting Started with Cell Renderers' for handling custom renderers. It is not exactly the same case but maybe it will come in handy for other users visiting this post.