10

I went through this post jQuery UI DatePicker to show month year only which is very helpful to me in order to hack the datetime picker UI to suit my situation.

But as I have several datetime picker on the same form, this happens. The css display:none is aim to 'hide' the days not to be shown. But if I have several datetime picker on the same form but only one I wish to make one of it monthpicker, how can I achieve that? With thw css, it makes all the days on the all datetime calender UI disappear since the css will change the attribute of .ui-datepicker-calendar. Any suggestions are welcome.

ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
Darren
  • 101
  • 1
  • 1
  • 3

7 Answers7

9

Currently, datepicker creates only 1 element per page that all 'datepicker' inputs share, hence why the answer to the linked question does not work. The beforeShow event does not allow editing the datepicker element with .addClass() or .css() (as the element structure is refreshed from the datepicker script when it shows.)

To get around this, I found that the focus event for the input element appears to run code after the datepicker is shown. It is a simple workaround to a frustrating problem.

Here is my code:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.js"></script>
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js"></script>
    <link rel="stylesheet" type="text/css" media="screen" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery-ui.css">
<script type="text/javascript">
$(function() {
    $('.month-picker').datepicker( {
        changeMonth: true,
        changeYear: true,
        showButtonPanel: true,
        dateFormat: 'MM yy',
        onClose: function(dateText, inst) { 
            var month = $("#ui-datepicker-div .ui-datepicker-month :selected").val();
            var year = $("#ui-datepicker-div .ui-datepicker-year :selected").val();
            $(this).datepicker('setDate', new Date(year, month, 1));
        },
        beforeShow : function(input, inst) {
            if ((datestr = $(this).val()).length > 0) {
                year = datestr.substring(datestr.length-4, datestr.length);
                month = jQuery.inArray(datestr.substring(0, datestr.length-5), $(this).datepicker('option', 'monthNames'));
                $(this).datepicker('option', 'defaultDate', new Date(year, month, 1));
                $(this).datepicker('setDate', new Date(year, month, 1));
            }
        }
    });
    $('.date-picker').datepicker();
    $('.month-picker').focus(function () {
        $('.ui-datepicker-calendar').addClass('hideDates');
    });
});
</script>
<style>
.hideDates {
    display: none;
}
</style>
</head>
<body>
    <label for="startDate">Date:</label>
    <input name="startDate" id="startDate" class="date-picker" />
    <label for="endMonth">End Month:</label>
    <input name="endMonth" id="endMonth" class="month-picker" />
</body>
</html>
Ben Koehler
  • 8,633
  • 3
  • 23
  • 23
  • What is the line calling the datepicker with empty parameter for? what does it do? – Nap Mar 31 '11 at 07:10
  • @Nassign - There are two datepickers on this page. The datepicker call with empty parameter is only to create the second datepicker with the default functionality. – Ben Koehler Mar 31 '11 at 13:02
  • Thanks. I found a site that adds custom button to the button panel. But the button disappear each time the month is changed and the Now button is changed. Any suggestion? Here is the site link : http://csharptechies.blogspot.com/2010/12/adding-custom-buttons-to-jquery.html – Nap Apr 01 '11 at 03:52
  • @Nassign - You will probably get a quicker and better answer if you create a new question. – Ben Koehler Apr 01 '11 at 14:06
  • Works well but I am getting a css positioning problem when the datepicker tries to appear above the input. I've raised a new question here: http://stackoverflow.com/questions/5816749/jquery-ui-datepicker-month-and-year-only-css-positioning-problem – benb Apr 28 '11 at 09:54
  • this solution has bug in IE.
    [jsfiddle link](http://jsfiddle.net/z1d44zdg/) try to click twice very fast in previous button of "end Month" date picker. the calendar no longer hide anymore. The reason is focus event doesnt fire in IE when you click very fast twice in previous (or next) button.
    – Chinh Phan May 25 '15 at 08:27
3

I used a slightly different version of the code that Ben posted. Instead of relying on the focus event I added

inst.dpDiv.addClass('monthonly');

into the beforeShow method and

inst.dpDiv.removeClass('monthonly');

into the onClose. This adds and removes a class on the common div used by the all the datepicker widgets. The date calendar div can then be targeted in css using

.monthonly#ui-datepicker-div .ui-datepicker-calendar
{
    display: none;
}
Mike
  • 857
  • 1
  • 16
  • 29
  • Wish I had read this. This approach prevents the positioning of the calendar being wrong when appearing above the input. (see: http://stackoverflow.com/questions/5816749/jquery-ui-datepicker-month-and-year-only-css-positioning-problem) – benb Apr 28 '11 at 16:25
2

Previous solution will not work with different formats. Also setDate will do nothing in beforeShow. Proper way to do it will be:

beforeShow: function(input, inst) {
    var dateString = $(this).val();
    var options = new Object();
    if (dateString.length > 0) {
        options.defaultDate = $.datepicker.parseDate("dd-" + $(this).datepicker("option", "dateFormat"), "01-" + dateString);
    }
    inst.dpDiv.addClass("ui-monthpicker");
    return options;
},
onClose: function(dateText, inst) {
    var month = inst.dpDiv.find(".ui-datepicker-month").val();
    var year = inst.dpDiv.find(".ui-datepicker-year").val();
    $(this).datepicker("setDate", new Date(year, month, 1));
    inst.dpDiv.removeClass("ui-monthpicker");
}

I used parseDate from datepicker to handle different date formats and return date from field as defaultDate option.

Required CSS:

#ui-datepicker-div.ui-monthpicker {
    padding: 0.2em;
}
#ui-datepicker-div.ui-monthpicker .ui-datepicker-calendar {
    display: none;
}
Zeljko
  • 21
  • 2
  • I added a timeout when removing the ui-monthpicker class, otherwise the calendar "flashes" before the datepicker is hidden. `setTimeout(function () { inst.dpDiv.removeClass("ui-monthpicker"); }, 200);` – user2444499 Aug 07 '14 at 01:01
2

I have yet another solution based on the above with some improvements. In my HTML I hide the day picker by adding this as I only have one on the page:

<style>
    .ui-datepicker-calendar {
        display: none;
    }
</style>

I then initialise my datepicker as others have done so and add a bit of code to the onChangeMonthYear event:

$n(this).datepicker({
    defaultDate: 0,
    changeMonth: true,
    changeYear: true,
    onChangeMonthYear: function(year, month, inst) {
        $(this).datepicker('setDate', new Date(year, month - 1, 1));
    }
});

Note: the

month - 1

If you don't add this you will get a stack overflow because this function receives a 1 based index month but setDate uses a normal 0 based month.

Oly
  • 31
  • 1
1

I did something similar to this, but made a seperate 'version' of the datepicker script and called it monthpicker, having it's own CSS selectors and CSS file. This meant you could use either or both on the same page.

Paddy
  • 33,309
  • 15
  • 79
  • 114
  • Hi Thanks for your kind reply, can explain further about it, alright I duplicate another .js file call monthpicker.js from jquery.ui.datetimepicker.js, so what should be the next step explain by you "having it's own CSS selectors and CSS file"? – Darren Nov 02 '10 at 16:18
  • @Darren - You need to pick through the code and see how the script is assigning selectors/ids to items that it creates and change them to use 'monthpicker' rather than 'datepicker' for example. You then need to copy the CSS file and make matching changes there. – Paddy Nov 02 '10 at 16:27
  • Well, just wonder whether I can use css inheritance to just select the class .ui-datepicker-calendar which belongs to my only datepicker in ? – Darren Nov 02 '10 at 16:44
1

Ben's solution works perfectly, just made a minor change, I used onChangeMonthYear instead of onClose:

onChangeMonthYear: function(year, month, inst) {
  var date = new Date(year, month - 1, 1);
  $(this).val($.datepicker.formatDate(format, date));
  $(this).datepicker('setDate', date);
}
rubish
  • 10,887
  • 3
  • 43
  • 57
0

This code is working flawlessly to me:

$(document).ready(function()
{   
    $(".monthPicker").datepicker({
        dateFormat: 'MM yy,
        changeMonth: true,
        changeYear: true,
        showButtonPanel: true,

        onClose: function(dateText, inst) {
            var month = $("#ui-datepicker-div .ui-datepicker-month :selected").val();
            var year = $("#ui-datepicker-div .ui-datepicker-year :selected").val();
            $(this).val($.datepicker.formatDate('MM yy', new Date(year, month, 1)));
        }
    });

    $(".monthPicker").focus(function () {
        $(".ui-datepicker-calendar").hide();
        $("#ui-datepicker-div").position({
            my: "center top",
            at: "center bottom",
            of: $(this)
        });
    });
});

<label for="month">Month: </label>
<input type="text" id="month" name="month" class="monthPicker" />
Leniel Maccaferri
  • 100,159
  • 46
  • 371
  • 480