简体   繁体   English

UI Datepicker:选择日期会覆盖现有设置

[英]UI Datepicker: choosing date overwrites existing settings

I am trying to write a custom datepicker, where the default drop downs for months and year ranges (enabled through changeMonth and changeYear options) are replaced by custom drop downs. 我正在尝试编写一个自定义日期选择器,其中月份和年份范围的默认下拉(通过changeMonthchangeYear选项启用)将被自定义下拉列表替换。 It is something like this: 它是这样的:

Fiddle: http://jsfiddle.net/gGV3v/ 小提琴: http//jsfiddle.net/gGV3v/

$("#myId").datepicker({
   ...default settings...
   beforeShow: function() {
      ...here I replace the default dropdowns by custom dropdowns...
      ...something like...
      $(".ui-datepicker-month").replaceWith("#custom-html-block");
      $(".ui-datepicker-year").replaceWith("#another-custom-html-block");
    }
 });

On choosing either month or year from the custom dropdowns, I want to change the date in the view accordingly. 从自定义下拉列表中选择月份或年份时,我想相应地更改视图中的日期。 So I construct the date string from the current month and year (the date for the new month/year combo defaults to 1 here), and I call 所以我从当前月份和年份构建日期字符串(新月/年组合日期默认为1),我打电话

$("#custom-html-block .custom-dropdown-option").on("click",function() {
     ...construct newDateString...
     $("#myId").datepicker("setDate",newDateString)
});

$("#another-custom-html-block .custom-dropdown-option").on("click",function() {
     ...construct newDateString...
     $("#myId").datepicker("setDate",newDateString)
});

I want the span with text foo to remain intact when setting the new date programmatically on clicking it. 我希望在单击它时以编程方式设置新日期时,文本foospan保持不变。


The problem is: it wipes off the custom drop downs and the default ones come again. 问题是:它消除了自定义下拉菜单,默认值下降。 I tried to do things like this: 我试着做这样的事情:

$("#myId").datepicker($.extend({setDate: newDateString},oldSettings))

But it still doesn't work. 但它仍然无效。 How do I make this work? 我该如何工作?

You can set the value of the function $.datepicker._generateMonthYearHeader , the downside it that will be global for all datepicker in the page. 您可以设置函数$.datepicker._generateMonthYearHeader的值,它是页面中所有日期$.datepicker._generateMonthYearHeader器的全局缺点。

The sample is below: 样本如下:

$.datepicker._generateMonthYearHeader = function(inst, drawMonth, drawYear, minDate, maxDate,
        secondary, monthNames, monthNamesShort) {


    var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
        changeMonth = this._get(inst, "changeMonth"),
        changeYear = this._get(inst, "changeYear"),
        showMonthAfterYear = this._get(inst, "showMonthAfterYear"),
        html = "<div class='ui-datepicker-title'>",
        monthHtml = "";

    // year selection
    if ( !inst.yearshtml ) {
        inst.yearshtml = "";
        if (secondary || !changeYear) {
            html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
        } else {
            // determine range of years to display
            years = this._get(inst, "yearRange").split(":");
            thisYear = new Date().getFullYear();
            determineYear = function(value) {
                var year = (value.match(/c[+\-].*/) ? drawYear + parseInt(value.substring(1), 10) :
                    (value.match(/[+\-].*/) ? thisYear + parseInt(value, 10) :
                    parseInt(value, 10)));
                return (isNaN(year) ? thisYear : year);
            };
            year = determineYear(years[0]);
            endYear = Math.max(year, determineYear(years[1] || ""));
            year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
            endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
            inst.yearshtml += "<span class = 'dummy'>Foo</span> <select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>"
            for (; year <= endYear; year++) {
                inst.yearshtml += "<option value='" + year + "'" +
                    (year === drawYear ? " selected='selected'" : "") +
                    ">" + year + "</option>";
            }
            inst.yearshtml += "</select>";


            html += inst.yearshtml;
            inst.yearshtml = null;
        }
    }

And your fiddle: http://jsfiddle.net/gGV3v/2/ 你的小提琴: http//jsfiddle.net/gGV3v/2/

UPDATE: 更新:

Without the buttons, and using a better approach, now you have control of all generated HTML: 如果没有按钮,并使用更好的方法,现在您可以控制所有生成的HTML:

var oldGenerateHTML = $.datepicker._generateHTML;

function newGenerateHTML(inst) {
    var html = oldGenerateHTML.call(this, inst);
    var $html = $(html);
    $html.find('[data-handler=prev]').remove();
    $html.find('[data-handler=next]').remove();
    $html.find('[data-handler=selectMonth]').replaceWith('<span class="dummy">Foo</span>');
    return $html;
}

$.datepicker._generateHTML = newGenerateHTML;

Fiddle also updated: http://jsfiddle.net/gGV3v/4/ 小提琴也更新: http//jsfiddle.net/gGV3v/4/

In general this is why extend sucks. 总的来说,这就是为什么延伸很糟糕。 The parent (in your case datepicker) doesn't know anything about childs (your custom html). 父(在你的情况下是datepicker)对childs(你的自定义html)一无所知。 Everytime it refresh the view, your changes are lost. 每次刷新视图时,您的更改都会丢失。 This problem is usually solved using composition. 通常使用组合来解决该问题。 The goal is to create your own widget (I think that was the term in jQuery) that have datepicker as a local variable and to control _generateMonthYearHeader function calls. 目标是创建自己的小部件(我认为这是jQuery中的术语)将datepicker作为局部变量并控制_generateMonthYearHeader函数调用。 It's easy to say in theory but in practice (specially case with jQuery) is hard to achive. 在理论上很容易说,但在实践中(特别是jQuery的情况)很难实现。 Easier solution will be to proxy the function. 更容易的解决方案是代理该功能。

//preserve _generateHTML because after it finish, html is visible and .ui-datepicker-month and .ui-datepicker-year are in dom tree
fn = $.datepicker._generateHTML; //preserve original function
$.datepicker._generateHTML = function(inst) {
    //call original function
    fn.call(this, inst);
    //do custom changes
    //you'll need better selectors in case of multiple datepicker instances
    $(".ui-datepicker-month").replaceWith("#custom-html-block");
    $(".ui-datepicker-year").replaceWith("#another-custom-html-block");   
}

Personally I dislike this approach (I prefer composition as I said) but in your case it'll be easier to implement. 就个人而言,我不喜欢这种方法(我更喜欢像我说的那样),但在你的情况下,它会更容易实现。 The reason its easier is because generateMonthYearHeader is called from many different functions. 它更容易的原因是因为从许多不同的函数调用generateMonthYearHeader。

PS Not tested PS未经测试

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM