Which way to add text to jquery ui datepicker cell

2019-03-16 00:21发布

I need to show custom text on some dates at Jquery UI datepicker, to be more precise, to render a specific price for some dates. My idea was to use beforeShowDay to attach specific price in titles of such dates and then, in beforeShow to check out each td and to place title's text into the cell. Example:

var m, d, y, checkDate, specificPrice = '';    
var specificPrices = {"2013-3-8":"300 EUR", "2013-2-26":"263 EUR"}

$('#my-datepicker').datepicker({
    beforeShowDay:     function checkAvailable(date) {
    m = date.getMonth();
    d = date.getDate();
    y = date.getFullYear();
    checkDate = y + '-' + (m+1) + '-' + d;
    if(specificPrices[checkDate]){
        specificPrice = specificPrices[checkDate];
    }else{
        specificPrice = '';
    }
    return [true, "", specificPrice];
},
    beforeShow: function(elem, inst){
        $('table.ui-datepicker-calendar tbody td', inst.dpDiv).each(function(){
            var calendarPrice = $(this).attr('title');
            if(calendarPrice != undefined){
                $(this).find('a').append('<span class="calendar-price">' + calendarPrice + '<span>');
            }
        });         
    }
});

This will render prices on first calendar render (before month/year are changed) and for the inline calendar only.

I need prices to be shown on not-inline calendar and on any month/year change as well.

I tried some other variants, and tried to use onChangeMonthYear, but with no success so far.

Thank you for the attention, your ideas are welcome.

2条回答
叛逆
2楼-- · 2019-03-16 01:05

Based on @PrestonS's answer and this post, I have a nice simple solution that doesn't need to add <style> tags to header.

My solution updates Preston's as such:

ModifiedupdateDatePickerCells function:

function updateDatePickerCells(dp) {
    /* Wait until current callstack is finished so the datepicker
       is fully rendered before attempting to modify contents */
    setTimeout(function () {
        //Fill this with the data you want to insert (I use and AJAX request).  Key is day of month
        //NOTE* watch out for CSS special characters in the value
        var cellContents = {1: '20', 15: '60', 28: '100'};

        //Select disabled days (span) for proper indexing but apply the rule only to enabled days(a)
        $('.ui-datepicker td > *').each(function (idx, elem) {
            var value = cellContents[idx + 1] || 0;

            /***** MAGIC! *****/

            $(this).attr('data-content', value);

            // and that's it! (oh, so easy)
        });
    }, 0);
}

With this solution, you don't need the addCSSRule function at all.

Modified css:

/* to target all date cells */
.ui-datepicker td > *:after {
    content: attr(data-content);  /***** MAGIC! *****/

    /* add your other styles here */
}

/* to target only allowed date cells */
.ui-datepicker td > a:after {
}

/* to target only disabled date cells */
.ui-datepicker td > span:after {
}

Initializing with the datepicker object

If you need the datepicker object in the updateDatePickerCells function, here is a way to get it at initialization time. (Based on this post)

var calendarElem = $('#DatePicker').datepicker({
    changeMonth: true,
    changeYear: true,
    minDate: 0,
    //The calendar is recreated OnSelect for inline calendar
    onSelect: function (date, dp) {
        updateDatePickerCells( dp );
    },
    onChangeMonthYear: function(month, year, dp) {
        updateDatePickerCells( dp );
    },
    beforeShow: function(elem, dp) { //This is for non-inline datepicker
        updateDatePickerCells( dp );
    }
});

var datepicker = $.datepicker._getInst(calendarElem[0]);
updateDatePickerCells(datepicker);
查看更多
The star\"
3楼-- · 2019-03-16 01:21

I came across this same scenario and thought I would post my solution for an inline datepicker but should work for a popup datepicker as well.

First of all, you cannot modify the contents of the table cells created by the datepicker plugin. Doing so will break its core functionality as it reads the cell content to generate the selected date string. So, the contents must be added using pure css.

Create your datepicker

$('#DatePicker').datepicker({
    changeMonth: true,
    changeYear: true,
    minDate: 0,
    //The calendar is recreated OnSelect for inline calendar
    onSelect: function (date, dp) {
        updateDatePickerCells();
    },
    onChangeMonthYear: function(month, year, dp) {
        updateDatePickerCells();
    },
    beforeShow: function(elem, dp) { //This is for non-inline datepicker
        updateDatePickerCells();
    }
});
updateDatePickerCells();

Create the method to insert the cell content

function updateDatePickerCells(dp) {
    /* Wait until current callstack is finished so the datepicker
       is fully rendered before attempting to modify contents */
    setTimeout(function () {
        //Fill this with the data you want to insert (I use and AJAX request).  Key is day of month
        //NOTE* watch out for CSS special characters in the value
        var cellContents = {1: '20', 15: '60', 28: '100'};

        //Select disabled days (span) for proper indexing but apply the rule only to enabled days(a)
        $('.ui-datepicker td > *').each(function (idx, elem) {
            var value = cellContents[idx + 1] || 0;

            /* dynamically create a css rule to add the contents with the :after                         
               selector so we don't break the datepicker functionality */
            var className = 'datepicker-content-' + value;

            if(value == 0)
                addCSSRule('.ui-datepicker td a.' + className + ':after {content: "\\a0";}'); //&nbsp;
            else
                addCSSRule('.ui-datepicker td a.' + className + ':after {content: "' + value + '";}');

            $(this).addClass(className);
        });
    }, 0);
}

Add a method to create new CSS rules on the fly, while keeping track of ones already created.

var dynamicCSSRules = [];
function addCSSRule(rule) {
    if ($.inArray(rule, dynamicCSSRules) == -1) {
        $('head').append('<style>' + rule + '</style>');
        dynamicCSSRules.push(rule);
    }
}

And finally, some default css for the new cell content

.ui-datepicker td a:after
{
    content: "";
    display: block;
    text-align: center;
    color: Blue;
    font-size: small;
    font-weight: bold;
}  

This works for basic content, but if you want to get fancy with something like '$20.95' (contains CSS special characters), you could use an md5 hash of the content to create the className variable.

EDIT JSFiddle modified from @yuga's JSFiddle to include an MD5 hash of the unique class name for more complicated contents.

查看更多
登录 后发表回答