使用 jquery-ui datepicker 的 knockoutjs 数据绑定

Posted

技术标签:

【中文标题】使用 jquery-ui datepicker 的 knockoutjs 数据绑定【英文标题】:knockoutjs databind with jquery-ui datepicker 【发布时间】:2011-09-17 22:48:26 【问题描述】:

我正在使用jQuery UI 日期选择器。它后面的 html 输入字段目前作为dependentObservable 挂接到KnockoutJS,但是当在视图模型中设置它的值时,日期选择器会丢失它的格式。

我应该如何做到这一点而不丢失格式?我希望 viewModel 不知道它是 jQuery datepicker。

【问题讨论】:

【参考方案1】:

您可以编写一个自定义绑定,使用 datepicker API 在字段中设置日期,并通过正确读取日期来设置您的 observable 的值。

自定义绑定可能如下所示:

ko.bindingHandlers.datepicker = 
    init: function(element, valueAccessor, allBindingsAccessor) 
        var options = allBindingsAccessor().datepickerOptions || ,
            $el = $(element);

        //initialize datepicker with some optional options
        $el.datepicker(options);

        //handle the field changing
        ko.utils.registerEventHandler(element, "change", function() 
            var observable = valueAccessor();
            observable($el.datepicker("getDate"));
        );

        //handle disposal (if KO removes by the template binding)
        ko.utils.domNodeDisposal.addDisposeCallback(element, function() 
            $el.datepicker("destroy");
        );

    ,
    update: function(element, valueAccessor) 
        var value = ko.utils.unwrapObservable(valueAccessor()),
            $el = $(element),
            current = $el.datepicker("getDate");

        if (value - current !== 0) 
            $el.datepicker("setDate", value);   
        
    
;

你会像这样使用它:

<input data-bind="datepicker: myDate, datepickerOptions:  minDate: new Date() " />

datepickeroptions 是可选的,可以包含您想要传递给 datepicker() 调用的任何内容。

此外,这假设您正在使用可观察的日期。如果您想与不可观察对象进行单向绑定,则绑定必须做更多的工作,但这不太可能。

示例:http://jsfiddle.net/rniemeyer/NAgNV/

【讨论】:

这个自定义绑定需要如何更改才能更好地在 datepicker 和“with: submodelObject”样式绑定之间进行协作?在我的使用中,它导致日期选择器的 div 最终呈现为可见,直到它可以附加到可见的 ;不过,使用“模板:afterRender:jqueryDecoratingMethod,数据:submodelObject”效果很好。 @TetsujinnoOni 你有你在哪里看到问题的样本吗?很乐意看看。 Ryan - 感谢您的提议;我无法在小提琴中重现。我怀疑(由于页面上的其他丑陋)我要么忘记了主题 jqueryui 要么在我的 CSS 中发生了类似的丑陋......如果我可以将其缩小到特定的因素组合,我会发布一个链接或一个小提琴。 我意识到这已经很老了,但是当我尝试将它用于日期时间选择器时,在 IE7 中,弹出窗口不会完全消失。当我选择一个值时,它会短暂隐藏弹出窗口,然后再次激活,没有任何方法可以关闭它。对这个错误有什么想法吗?在 Chrome 中似乎很好。 @Zero21xxx 我更新了答案并进行了调整,以防止在 IE7 上出现此问题。这在某个时候出现在另一个问题中。【参考方案2】:

我必须对 RP Niemeyer 的代码稍作修改才能使用 dateFormat 选项在我的代码中工作,替换

$(element).datepicker("getDate")

$(element).val()

因此,日期的格式化版本在后台正确传递。

【讨论】:

【参考方案3】:

我一直在使用上面标记为答案的 RP Niemeyer 的代码,但是自从我一直在使用它以来,我对其进行了一些小改动。我以为我会在这里发帖。也许它会帮助别人。这几乎是一样的,唯一的区别是如果元素在页面加载时有一个值,那么它将保留它的值。另外,我将$elem 设置为变量,这样jQuery 必须对$(element) 进行更少的处理。

ko.bindingHandlers['jqDatePicker'] = 
    'init': function(element, valueAccessor, allBindingsAccessor) 
        /* Initialize datepicker with some optional options */
        var options = allBindingsAccessor().jqDatePickerOptions || ,
            prop = valueAccessor(),
            $elem = $(element);

        prop($elem.val());

        $elem.datepicker(options);

        /* Handle the field changing */
        ko.utils.registerEventHandler(element, "change", function () 
            prop($elem.datepicker("getDate"));
        );

        /* Handle disposal (if KO removes by the template binding) */
        ko.utils.domNodeDisposal.addDisposeCallback(element, function() 
            $elem.datepicker("destroy");
        );
    ,
    'update': function(element, valueAccessor) 
        var value = ko.utils.unwrapObservable(valueAccessor()),
            $elem = $(element),
            current = $elem.datepicker("getDate");

        if (value - current !== 0) 
            $elem.datepicker("setDate", value);
        
    
;

【讨论】:

我没有深入研究,但是日期选择器的初始值没有设置为绑定的 observable 的值。【参考方案4】:

以下是适合我特定情况的方法。我正在运行一个足够新的 MVC 版本,默认日期时间序列化程序以 ISO 8601 呈现(请参阅 On the nightmare that is JSON Dates. Plus, JSON.NET and ASP.NET Web API)。我的绑定直接写入日期选择器,而是写入输入标签的“值”属性。

另外,值得注意的是,我使用的是date.js

ko.bindingHandlers.dateValue = 
    update: function(element, valueAccessor, allBindingsAccessor, viewModel) 
        var value = valueAccessor(),
            allBindings = allBindingsAccessor();
        var valueUnwrapped = ko.utils.unwrapObservable(value);
        var pattern = allBindings.datePattern || 'MM/dd/yyyy';
        var date = Date.parse(valueUnwrapped)
        $(element).val(date.toString(pattern));
    ,

    init: function(element, valueAccessor, allBindingsAccessor) 
        //handle the field changing
        ko.utils.registerEventHandler(element, "change", function () 
            var observable = valueAccessor();
            var date = Date.parse($(element).val());
            observable(date.toString("yyyy-MM-ddThh:mm:ss"));
        );
    

绑定如下:

<input class="date" type="text" data-bind="dateValue: SomeViewModelDate" />

以及开启日期选择器的 javascript 代码:

$(document).ready(function () 
    $('.date').datepicker( dateFormat: "mm/dd/yy" );
);

【讨论】:

我有一个问题,我应该在应用绑定之前将代码放在哪里?现在我收到错误:未捕获类型错误:无法处理绑定“foreach:函数()返回策略”消息:无法处理绑定“dateValue:函数()return startDate”消息:无法读取属性'toString ' 为空【参考方案5】:

当用户从 datepicker 控件中选择新日期时,上面的 datepicker 示例将 viewmodel 中的日期格式从 WCF 格式更改为 JavaScript 日期格式。

在我的例子中,我将日期传递回 WCF 服务,它不接受反序列化的 JavaScript 日期,它需要 WCF 格式的日期。我修改了上面的脚本,以便它以 WCF 格式将日期存储在视图模型中,以便可以以该格式将其发送回服务器。

ko.bindingHandlers.datepicker = 
    init: function (element, valueAccessor, allBindingsAccessor) 
        //Initialize datepicker with some optional options
        var options = allBindingsAccessor().datepickerOptions || ;
        $(element).datepicker(options);
        //Handle the field changing
        ko.utils.registerEventHandler(element, "change", function () 
            var observable = valueAccessor();
            // observable($(element).datepicker("getDate"));
            // store the date in 'WCF String format"
            var tempdate=$(element).datepicker("getDate");
            var tempdatestr="/Date("+tempdate.getTime()+")/";
            observable(tempdatestr);
        );
        //Handle disposal (if KO removes by the template binding)
        ko.utils.domNodeDisposal.addDisposeCallback(element, function () 
            $(element).datepicker("destroy");
        );
    ,
    update: function (element, valueAccessor) 
        var value = ko.utils.unwrapObservable(valueAccessor());
        //Handle date data coming via JSON from Microsoft
        if (String(value).indexOf('/Date(') == 0) 
            value = new Date(parseInt(value.replace(/\/Date\((.*?)\)\//gi, "$1")));
        
        current = $(element).datepicker("getDate");
        if (value - current !== 0) 
            $(element).datepicker("setDate", value);
        
    
;

【讨论】:

【参考方案6】:

一种解决方案是在dependentObservable 函数中自己格式化日期。所以你必须在函数中返回类似return viewModel.someOtherObservable() 的东西。格式化返回值。

如果你包含你的代码,我可以解释更多。

【讨论】:

【参考方案7】:

在dependentObservable 中格式化日期(到 mm/dd/yyyy)正是我想知道的。如果您能提供帮助,我会发布一些我的代码,Peter Mortensen 和/或 nEEBz。

    <div data-bind="with: technology">  
        <div class="titleblock">
            <label><b>End of Life Date</b></label> 
            <Input  type="text" class="ui-datepicker" id="datepicker" data-bind="value: END_OF_LIFE_DATE"/>
        </div>       
    </div>

在 ViewModel - technologydetail.js 中:

var technology = ko.observable();

在激活中:

return dataContext.getTechnologyById(currentTechnologyId, technology);

这会在文本框中显示如下所示的日期:Wed Jan 29 19:00:00 EST 2014 但是 我希望它只显示:01/29/2014。我正在使用这个 datepicker 选项 - dateFormat: "mm/dd/yy" 但它对显示的初始值没有影响。

我能够使用 moment 对其进行格式化,并且它可以很好地显示当前数据库值,但它似乎正在破坏与 observable 的绑定,因为它将不再在 SAVE 上更新。

<Input type="text" class="ui-datepicker" id="datepicker" data-bind="value: moment(END_OF_LIFE_DATE()).format('MM/DD/YYYY')" />

【讨论】:

以上是关于使用 jquery-ui datepicker 的 knockoutjs 数据绑定的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 5.5 中的 Datepicker 使用 Jquery-ui 或 Bootstrap

如何使用 NPM 同时获得 JQuery-UI 和 datepicker 本地化?

使用 jquery-ui datepicker 的 knockoutjs 数据绑定

jquery-ui datepicker 设置开始结束时间选择范围

在 jquery-ui datepicker 中的“今天”按钮上添加事件侦听器

Rails 服务器告诉我 --- 找不到类型为 'application/javascript' 的文件 'jquery-ui/datepicker'