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

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

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

【问题讨论】:

    标签: jquery-ui knockout.js


    【解决方案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')" />
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-03-22
            • 1970-01-01
            • 2013-01-03
            • 2015-02-26
            • 2016-09-18
            • 1970-01-01
            • 1970-01-01
            • 2011-10-05
            相关资源
            最近更新 更多