2

jqGrid date column for inline editing is defined using colmodel and javascript below.

It uses jquery ui-date picker. This is lot of code to maintain and result is ugly.

How to use html5 native input type='date' for inline date editing if this is supported by browser instead of this code ?

colmodel:

{"template":DateTemplate
,"label":"Invoice date",
"name":"Invoicedate",
"index":"Invoicedate",
"editoptions":{
  "dataInit":initDateWithButton
  ,"size":10
  },

"searchoptions":{"dataInit":initDateWithButton
,"size":10,"attr":{"size":10}},"width":50
}

javascript:

var DateTemplate = {
    sorttype: 'date', formatter: 'date',
    formatoptions: {
        srcformat: "Y-m-d"
    },

    editoptions: { maxlength: 10, size: 10, dataInit: initDateWithButton },
    editable: true,
    searchoptions: {
        sopt: ['eq', 'ne', 'lt', 'le', 'gt', 'ge'],
        dataInit: initDateWithButton,
        size: 11,          // for the advanced searching dialog 
        attr: { size: 11 }   // for the searching toolbar 
    }
};

var initDateWithButton = function (elem) {
    if (/^\d+%$/.test(elem.style.width)) {
        // remove % from the searching toolbar 
        elem.style.width = '';
    }
    // to be able to use 'showOn' option of datepicker in advance searching dialog 
    // or in the editing we have to use setTimeout 
    setTimeout(function () {
        $(elem).css({ "box-sizing": "border-box", width: "5.7em" }).datepicker({
            // dateFormat: 'dd.mm.yy',
            showOn: 'button',
            changeYear: true,
            changeMonth: true,
            showWeek: true,
            showButtonPanel: true,
            onClose: function (dateText, inst) {
                inst.input.focus();
            }
        })
            .removeClass("ui-corner-all").addClass("ui-corner-left");

        $(elem).next('button.ui-datepicker-trigger').button({
            text: false,
            icons: { primary: 'ui-icon-calendar' }
        }).css({ width: '1em', height: '1.09em' })
            .removeClass("ui-corner-all").addClass("ui-corner-right")
        .find('span.ui-button-text')
        .css({ padding: '0.1em' })
        .siblings('span.ui-button-icon-primary')
        .css({ marginLeft: "-8.5px", marginTop: "-8.5px" });
        $(elem).next('button.ui-datepicker-trigger').andSelf().css("verticalAlign", "middle");
    }, 100);
};

This is ASP.NET MVC4 application.

Update

I tried answer but got issues.

  1. Date template in question does not contain newformat so this is still not defined. I replaced date parsing line with line

    $(elem).val($.jgrid.parseDate($.jgrid.formatter.date.newformat, orgValue, "Y-m-d"));
    

as recommended in comment.

  1. Line str = $.jgrid.parseDate("Y-m-d", $this.val(), cm.formatoptions.newformat);

convets valid date which is already converted to iso, like 1973-02-15 to long format like Thu Feb 15 1973 00:00:00 GMT+0200 (FLE Standard Time)

Required result is 1973-02-15 so conversion is not needed.

I solved this by replacing line

$this.val(str);

with

$this.val($this.val());

  1. After date inline edit is finished, date is shown in column in iso format. Localized date is shown only after grid is refreshed.

** Update **

Date does not fit to column width. In IE button is visible:

iebutton

but in Chrome for same column width big empty space appears and only part of first button is visible:

chrome

How to fix this so that buttons are visible for same column width ?

Andrus
  • 26,339
  • 60
  • 204
  • 378

1 Answers1

3

I find your question interesting and created the demo which works in Google Chrome without jQuery UI Datepicker and display during date editing the results like

enter image description here

The demo have column invdate defined as below

{ name: "invdate", width: 120, align: "center", sorttype: "date",
    formatter: "date", formatoptions: { newformat: "m/d/Y"}, editable: true,
    editoptions: { dataInit: initDateEdit } }

The callback function initDateEdit I defined as

var initDateEdit = function (elem, options) {
    // we need get the value before changing the type
    var orgValue = $(elem).val(),
        cm = $(this).jqGrid("getColProp", options.name);

    $(elem).attr("type", "date");
    if ((Modernizr && !Modernizr.inputtypes.date) || $(elem).prop("type") !== "date") {
        // if type="date" is not supported call jQuery UI datepicker
        $(elem).datepicker({
            dateFormat: "mm/dd/yy",
            autoSize: true,
            changeYear: true,
            changeMonth: true,
            showButtonPanel: true,
            showWeek: true
        });
    } else {
        // convert date to ISO
        $(elem).val($.jgrid.parseDate.call(this, cm.formatoptions.newformat, orgValue, "Y-m-d"));
    }
};

I don't know <input type="date"/> good enough. It uses input format of date as ISO. So I converted in the code above the original text to ISO to display correct date during editing. In the same way one have to convert the results of editing back to the formatoptions.newformat. I used beforeSaveRow callback in the case:

onSelectRow: function (rowid) {
    var $self = $(this),
        savedRow = $self.jqGrid("getGridParam", "savedRow");
    if (savedRow.length > 0 && savedRow[0].id !== rowid) {
        $self.jqGrid("restoreRow", savedRow[0].id);
    }
    $self.jqGrid("editRow", rowid, {
        keys: true,
        beforeSaveRow: myBeforeSaveRow
    });
}

where myBeforeSaveRow are defined as the following:

var myBeforeSaveRow = function (options, rowid) {
    var $self = $(this), $dates = $("#" + $.jgrid.jqID(rowid)).find("input[type=date]");
    $dates.each(function () {
        var $this = $(this),
            id = $this.attr("id"),
            colName = id.substr(rowid.length + 1),
            cm = $self.jqGrid("getColProp", colName),
            str;
        if ((Modernizr && Modernizr.inputtypes.date) || $this.prop("type") === "date") {
            // convert from iso to newformat
            str = $.jgrid.parseDate.call($this[0], "Y-m-d", $this.val(), cm.formatoptions.newformat);
            $this.attr("type", "text");
            $this.val(str);
        }
    });
};

UPDATED: One more demo supports better Opera 24 and empty input dates.

UPDATED 2: The demo contains small modification (the setting of this for $.jgrid.parseDate) and it uses free jqGrid 4.8.

Oleg
  • 220,925
  • 34
  • 403
  • 798
  • I tried it but got error since options parameter is undefined. I updated question. – Andrus Oct 01 '14 at 21:25
  • @Andrus: jqGrid 4.4.5 is more as 1.5 year old. The second `options` parameter of `dataInit` was added in 4.5.4 one year ago. So you should either update jqGrid which you use or to use something like `dataInit: function (elem) { return initDateWithButtonHTML5.call(this, elem, {name: "columnName"}); }` instead of `dataInit: initDateWithButtonHTML5`. Alternatively you can just use fixed date format which you use instead of `cm.formatoptions.newformat`. In the case you will don't need `cm` and `options.name`. – Oleg Oct 01 '14 at 21:58
  • As shown in code in question, source date values are in ISO format accepted by input type='date' . input element performs convertsion to/from iso format automatically from date shown in browser. Should we remove format conversion and myBeforeSaveRow from this code ? – Andrus Oct 02 '14 at 13:06
  • @Andrus: If you read the code of `initDateEdit` from my answer you will see that thesecond `options` parameter will be used to get `cm.formatoptions.newformat` (see the first parameter of `$.jgrid.parseDate`). So if you know `newformat` then you can use it directly in the value of `newformat` property from `formatoptions` or `$.jgrid.formatter.date.newformat`. In the case you should remove additionally the second `options` parameter of `initDateWithButtonHTML5` and the line `cm = $(this).jqGrid("getColProp", options.name)` too. – Oleg Oct 02 '14 at 16:09
  • @Andrus: Inside of `myBeforeSaveRow` you need just replace `cm.formatoptions.newformat` to `cm.formatoptions.newformat || $.jgrid.formatter.date.newformat` – Oleg Oct 02 '14 at 16:11
  • 4.4.5 source code does not contain `beforeSaveRow` . How to use this in 4.4.5 or should I upgrade ? I have added changes to jqgrid source code from your answers, so I must apply those changes manually and test again. This is lot of work. – Andrus Oct 03 '14 at 10:46
  • @Andrus: **I recommend you to update to the latest version of jqGrid**. The goal of stackoverflow is providing solutions which can have values for **many people**. Creating solutions for some old version have some value for you only. Only if you really can't update jqGrid because of some project specific reasons you can create the solution of your problem yourself. I think it's possible using `serializeRowData` or successfunc or `aftersavefunc` or by "subclassing" `saveRow` method (see [the answer](http://stackoverflow.com/a/12400928/315935) for an example of "subclassing"). – Oleg Oct 03 '14 at 10:59
  • @Andrus: I tried to explain you in my previous comment that updating jqGrid to 4.6.0 (or higher which will be hopefully published soon) is **the way** to solve the problem. If you do want to create the implementation with jqGrid 4.4.5 I think it's possible based on *the idea* from my answer, but you have to write the implementation yourself. You can't use my code directly because a lot of changes in jqGrid between 4.4.5 and 4.6.0, you can just use *the idea*. Just an example `parseDate` have **2 options** `format, date` in 4.4.5 and **4 options** `format, date, newformat, opts` in 4.6.0. – Oleg Oct 04 '14 at 21:18
  • I upgraded to 4.6.0 . Those issues occur in 4.6.0 and one can reproduced in your sample as described. – Andrus Oct 04 '14 at 21:20
  • @Andrus: Which test case in [my demo](http://www.ok-soft-gmbh.com/jqGrid/dateInput.htm) to reproduce the problem? What is the current problem? – Oleg Oct 04 '14 at 21:22
  • This is described in issue 3: double click in date column to edit in Chrome. Press x in right side to clear date. Press Enter. Observed: year 1970 date appears. Expected: date column should represent empty date (null value) – Andrus Oct 04 '14 at 21:48
  • @Andrus: It has no relation to the main part of my answer and can be fixed in less as one min. See [the modified demo](http://www.ok-soft-gmbh.com/jqGrid/dateInput_.htm). – Oleg Oct 05 '14 at 08:54
  • Thank you. It worked. Now refresh 4th issue in question remains unresolved. Another issue: ff column width is small, buttons are not visible (if datepicker is used, calendar button appears in next row in this case). How to show buttons also if column width is small. Why demo code uses `$(elem).css("width", "")` which is not in answer? – Andrus Oct 05 '14 at 09:11
  • @Andrus: The line `$(elem).css("width", "")` just removes `width: 98%;` which jqGrid set on standard `` inline editing fields. It seems to me that the setting don't help in case of usage `type="date"`. I makes some other small changes in the code of demo after I posted the answer. I changed for example `width: 130` to `width: 120`. **I'm not sure which behavior you expect in case of usage `` with small width.** Default behavior: one can use keyboard arrows (right & left) to move cursor or to edit (up & down). One can also press keys with numbers, Esc and Enter. – Oleg Oct 05 '14 at 11:03
  • `$(elem).css("width", "9.6em")` decreases width so that there is no empty space before date edit delete icon and whole date is visible in search toolbar and inline edit. How to replace 9.6em with something more generic ? – Andrus Oct 14 '14 at 17:57
  • @Andrus: I don't know an *universal* value for `width`. The best value depend on how the web browser build the control. In [the last demo](http://www.ok-soft-gmbh.com/jqGrid/dateInput_.htm) which I posted in my answer I used `$(elem).css("width", /OPR/.test(navigator.userAgent) ? "11em": "10em");` to set 10em for Chrome and 11em for Opera 24. You can test your cases and choose any other `width` value (`"96%"` for example) which more corresponds your requirements. – Oleg Oct 14 '14 at 19:33
  • If row is added or edited using form, entered date value is not saved if this code is used. In Chrome date entry control appers properly but changed value is not saved. How to save date from form also ? – Andrus Feb 24 '15 at 17:57
  • @Andrus: I used *inline editing* in my demos. If you use form editing you should provide *your demo*. There are some common problems with editing of dates in jqGrid which I fixed in [my fork](https://github.com/free-jqgrid/jqGrid). The usage of `reformatAfterEdit: true` can be important for old jqGrid versions. I recommend you to read [the post](https://github.com/openpsa/jsgrid/issues/43#issuecomment-71252518) where I described the problem in details with many demos and the exact test case. – Oleg Feb 24 '15 at 18:10
  • I'm using reformatAfterEdit: true. I read your post but havent found solution. I posted it as separate question in http://stackoverflow.com/questions/28705182/how-to-use-html5-input-type-date-in-form-edit-in-jqgrid – Andrus Feb 24 '15 at 20:03
  • 1
    In 4.8 line `$(elem).val($.jgrid.parseDate($.jgrid.formatter.date.newformat, orgValue, "Y-m-d"))` causes exception `Cannot read property 'replace' of undefined` It looks like `$.jgrid.formatter.date.newformat` is undefined – Andrus Mar 16 '15 at 07:14
  • @Andrus: it's correct. One have to use `$.jgrid.parseDate.call($self[0], ...)`. It's required because of [the line](https://github.com/free-jqgrid/jqGrid/blob/master/js/grid.base.js#L507) which get `formatter.date` depend on the grid locale. – Oleg Mar 16 '15 at 07:21
  • I tried but got exception that $self is not defined. It looks like $self is out of scope in this call – Andrus Mar 16 '15 at 08:20
  • @Andrus: I appended the answer with [the modified demo](http://www.ok-soft-gmbh.com/jqGrid/OK/dateInput_48.htm) and included the corresponding information in the Readme of free jqGrid 4.8. – Oleg Mar 16 '15 at 08:21
  • This requires specifying date format in every column in colmodel. If date format is not specified `cm.formatoptions.newformat` is undefined and exception occurs. How to fall back to default locale date format if date format is not specified in colmodel so that same colmodel supports multiple locales automatically ? – Andrus Mar 16 '15 at 09:06
  • I'm using always default locale date format and never set date format in colmodel. Using $.jgrid.formatter.date.newformat worked well in this case earlier. – Andrus Mar 16 '15 at 09:18
  • @Andrus: You should forget `$.jgrid.formatter....` which is not more exists in free jqGrid 4.8 (like in the current code of jqGrid too). There are locale between `$.jgrid` and `formatter.date.newformat` (like `$.jgrid.locales["en-US"].formatter.date.newformat` or `$.jgrid.locales.de.formatter.date.newformat`). So it's better to use `getGridRes` to get the strings: `$grid.jqGrid("getGridRes", "formatter.date.newformat")`. I updated [the demo](http://www.ok-soft-gmbh.com/jqGrid/OK/dateInput_48.htm). – Oleg Mar 16 '15 at 09:48
  • @Andrus: Tony implemented the changes in his code based on [my old](http://www.trirand.com/blog/?page_id=393/feature-request/small-changes-in-i18ngrid-locale-xx-js-files-to-make-possible-dynamic-language-switching). So the names of properties are a little different. He uses `$.jgrid.regional["en-US"]` and I use `$.jgrid.locales["en-US"]`. Moreover I added `getGridRes` and he uses `$.jgrid.getRegional`. The logic of `getGridRes` and `$.jgrid.getRegional` is a little different too. In any way you should not use localized stings like `$.jgrid.formatter.date.newformat`. – Oleg Mar 16 '15 at 09:53
  • @Andrus: I would recommend you to search your existing code for `$.jgrid.formatter`, `$.jgrid.defaults`, `$.jgrid.search`, `$.jgrid.edit`, `$.jgrid.view`, `$.jgrid.del`, `$.jgrid.nav`, `$.jgrid.col`, `$.jgrid.errors`. You can still *set* defaults options using the objects, but you should use **deep** version: `$.extend(true, ...);`. If you need *get* any localized value from above parts of settings you should always use `getGridRes` method now. – Oleg Mar 16 '15 at 09:59