Html 使用 Knockout.js 如何将 Date 属性绑定到 HTML5 日期选择器?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18016718/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-29 11:48:28  来源:igfitidea点击:

Using Knockout.js how do bind a Date property to a HTML5 date picker?

javascripthtmlknockout.js

提问by Ryan

(this only works in Chrome at the moment as most browsers don't yet implement date picker for input type="date")

(目前这只适用于 Chrome,因为大多数浏览器还没有为 input type="date" 实现日期选择器)

In the following example MyDate starts out as a Date object with the current date, but this isn't picked up by the date input (which expects its format to be a string in format YYYY/MM/DD).

在下面的示例中,MyDate 以具有当前日期的 Date 对象开始,但这不会被日期输入(它期望其格式为 YYYY/MM/DD 格式的字符串)。

Once you've picked a date in the picker then MyDate becomes a string in format above.

在选择器中选择日期后,MyDate 将成为上述格式的字符串。

How can you bind this so MyDate stays a javascript Date and is interpreted by the input control correctly?

您如何绑定它,以便 MyDate 保持 javascript 日期并由输入控件正确解释?

See See http://jsfiddle.net/LLkC4/3/:-

http://jsfiddle.net/LLkC4/3/:-

<input data-bind="value : MyDate" type="date">
<hr>   
<span data-bind="html: log" />

<script>
var viewModel = {    
    MyDate : ko.observable(new Date()),
    log : ko.observable(""),
    logDate : function () { 
            this.log(this.log() + this.MyDate() + " : " +
                     typeof(this.MyDate()) + "<br>");
                     }
};

viewModel.MyDate.subscribe(function (date) {    
    viewModel.logDate();    
});

ko.applyBindings(viewModel);

viewModel.logDate()
</script>

采纳答案by Ryan

While @amakhrov answer will work (and would be even better if used writeable computed observable like sujested by @Stijn) I decided to do this using Custom Bindings.

虽然@amakhrov 的答案会起作用(如果使用@Stijn sujested 的可写计算可观察对象会更好),但我决定使用Custom Bindings来做到这一点。

The main advantage of doing this is reusability - I just have to use data-bind="datePicker : MyDate"whereever I want to tie this in. I can also modify other properties of the input element so this could be really useful if binding to complex jQuery (and other) controls.

这样做的主要优点是可重用性 - 我只需要在data-bind="datePicker : MyDate"任何我想将其绑定的地方使用。我还可以修改输入元素的其他属性,因此如果绑定到复杂的 jQuery(和其他)控件,这可能非常有用。

(Read here for more pro/consabout the 3 choices to do this sort of thing)

阅读此处了解有关执行此类操作的 3 种选择的更多利弊

HTML

HTML

<input data-bind="datePicker : MyDate" type="date">

JS

JS

ko.bindingHandlers.datePicker = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel) {                    
        // Register change callbacks to update the model
        // if the control changes.       
        ko.utils.registerEventHandler(element, "change", function () {            
            var value = valueAccessor();
            value(new Date(element.value));            
        });
    },
    // Update the control whenever the view model changes
    update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        var value =  valueAccessor();        
        element.value = value().toISOString();
    }
};

var viewModel = {    
    MyDate : ko.observable(new Date())
};     

ko.applyBindings(viewModel);

See http://jsfiddle.net/LLkC4/5/

http://jsfiddle.net/LLkC4/5/

回答by amakhrov

You can use the computed vartiable for the date object in your model:

您可以为模型中的日期对象使用计算变量:

In html:

在 HTML 中:

<input data-bind="value : rawDate" type="date">

In code:

在代码中:

var currentDate = (new Date()).toISOString().split('T')[0];

// this is used instead of MyDate in the data binding
rawDate : ko.observable(currentDate),

...
// and then set up the dependent variable
viewModel.MyDate = ko.computed(function () {
    var val = this.rawDate();
    if (typeof val === 'string') val = new Date(val);

    return val;
}, viewModel)

Please see the demo: http://jsfiddle.net/gcAXB/1/

请看演示:http: //jsfiddle.net/gcAXB/1/

回答by Justin

Here's a solution that is working for me with the latest knockoutjs, based off of the link below and modified to have a custom init function to handle updating ko.computed properties as your date value changes.

这是一个适用于我最新的 Knockoutjs 的解决方案,基于下面的链接,并修改为具有自定义 init 函数以在日期值更改时处理更新 ko.computed 属性。

Note that utils.formatDate is just a utility function to format the date in whatever string you want, so just replace that with your own date formatting code, whether you use momentjs or something else.

请注意, utils.formatDate 只是一个实用函数,用于将日期格式化为您想要的任何字符串,因此只需将其替换为您自己的日期格式化代码,无论您使用的是 momentjs 还是其他东西。

ko.bindingHandlers.date = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel) {    
        ko.utils.registerEventHandler(element, 'change', function () {
            var value = valueAccessor();

            if (element.value !== null && element.value !== undefined && element.value.length > 0) {
                value(element.value);
            }
            else {
                value('');
            }
        });
    },
    update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        var value = valueAccessor();
        var valueUnwrapped = ko.utils.unwrapObservable(value);

        var output = '';
        if (valueUnwrapped !== null && valueUnwrapped !== undefined && valueUnwrapped.length > 0) {
            output = utils.formatDate(valueUnwrapped);
        }

        if ($(element).is('input') === true) {
            $(element).val(output);
        } else {
            $(element).text(output);
        }
    }
};

    <div>
        <label>Date of Birth:</label>
        <input type="text" data-bind="date: dateOfBirth, format: 'DD MMM YYYY'" />
    </div>

BINDING AND FORMATTING DATES USING KNOCKOUT AND MOMENT JS

使用 Knockout 和 Moment JS 绑定和格式化日期

回答by brianlmerritt

These days is so much easier with Moment.js

现在使用 Moment.js 变得容易多了

this.sessionDate = ko.observable(moment().format('YYYY-MM-DD'));
this.getFormattedDate = () => { return moment(this.sessionDate()'YYYY-MM-DD').format('MM/DD/YYYY') }; // Note this is ES2015 syntax

In your html you can bind it with

在您的 html 中,您可以将其绑定

<input class="form-control" name="date" type="date" id="date" data-bind="value: sessionDate">

And display it formatted as

并将其显示为格式

<p data-bind="text : getFormattedDate()">Loading Date</p>

No need to create custom bindings, and you can use a shim for older browsers.

无需创建自定义绑定,您可以为旧浏览器使用 shim。

回答by Yannick Chartois

The same as this custom binding, but using momentJS:

此自定义绑定相同,但使用 momentJS:

ko.bindingHandlers.datePicker = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        // Register change callbacks to update the model
        // if the control changes.
        ko.utils.registerEventHandler(element, "change", function () {
            var value = valueAccessor();
            value(moment(element.value).format());
        });
    },
    // Update the control whenever the view model changes
    update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        var value =  valueAccessor();
        element.value = moment(value()).format("YYYY-MM-DD");
    }
};

回答by Brian Arsuaga

Based off of Ryan's answer above, this works a little nicer with newer ko/chrome widgets. It also strips the time part of the date.

根据上面 Ryan 的回答,这对于较新的 ko/chrome 小部件效果更好一些。它还去除了日期的时间部分。

ko.bindingHandlers.datePicker = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        // Register change callbacks to update the model
        // if the control changes.
        ko.utils.registerEventHandler(element, "change", function () {
            var value = valueAccessor();
            var target_date = element.valueAsDate;
            var truncated = new Date(target_date.getFullYear(), target_date.getMonth(), target_date.getDate());
            value(truncated);
        });
    },
    // Update the control whenever the view model changes
    update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        var value =  valueAccessor();
        var unwrapped = ko.utils.unwrapObservable(value());
        if(unwrapped === undefined || unwrapped === null) {
            element.value = '';
        } else {
            element.valueAsDate = unwrapped;
        }
    }
};

回答by user247702

From HTML 5 - Input type date formatting on iOS

来自HTML 5 - iOS 上的输入类型日期格式

There are two formats at play:

  • displayed format
  • internal format exposed to JavaScript and sent to the server

You cannot change the display format. It's up to the browser to decide how the date is presented to the user (in practice it's determined by system's locale).

You cannot change the internal format either. It's always ISO8601, regardless of browser/locale.

有两种格式在起作用:

  • 显示格式
  • 暴露给 JavaScript 并发送到服务器的内部格式

您无法更改显示格式。由浏览器决定如何向用户显示日期(实际上它由系统的区域设置决定)。

您也不能更改内部格式。无论浏览器/语言环境如何,它始终是 ISO8601。

You'll have to pre-populate it with that specific format, and you can add a computed observable to parse it into a Dateobject, so you can read it at other places in your application.

您必须使用该特定格式预先填充它,并且您可以添加一个计算的 observable 将其解析为一个Date对象,以便您可以在应用程序的其他位置读取它。

If you also want to write to it from JS, you could set up a writeable computed observableand parse the input to see if it's a string from the input field, or a Dateobject from your JS.

如果您还想从 JS 写入它,您可以设置一个可写的计算 observable并解析输入以查看它是来自输入字段的字符串还是Date来自您的 JS的对象。

回答by KillerKiwi

This worked for me

这对我有用

ko.bindingHandlers.momentDate = {
_parseDateTime: function (element, valueAccessor) {
    var value = valueAccessor();
    var valueUnwrapped = ko.utils.unwrapObservable(value);
    var datetime = moment(valueUnwrapped);
    var date = moment($(element).val(), 'YYYY-MM-DD');
    datetime = datetime.set({
        'year': date.get('year'),
        'month': date.get('month'),
        'date': date.get('date')
    });
    value(datetime.toDate());
},
init: function (element, valueAccessor) {
    function bind() {
        ko.bindingHandlers.momentDate._parseDateTime(element, valueAccessor);
    }
    $(element).change(bind).blur(bind);
},
update: function (element, valueAccessor) {
    var value = valueAccessor();
    var valueUnwrapped = ko.utils.unwrapObservable(value);
    var date = moment(valueUnwrapped);
    $(element).val(date.format('YYYY-MM-DD'));
}

};

};

<input type="date" data-bind="momentDate: $data.Date" class="form-control"/>