Подтвердить что ты не робот

Использование Knockout.js как связать свойство Date с выбором даты в формате HTML5?

(это работает только в Chrome на данный момент, так как большинство браузеров еще не реализует выбор даты для типа ввода = "дата" )

В следующем примере MyDate запускается как объект Date с текущей датой, но это не подхватывается вводом даты (который ожидает, что его формат будет строкой в ​​формате YYYY/MM/DD).

Как только вы выбрали дату в сборщике, MyDate станет строкой в ​​формате выше.

Как вы можете связать это так, чтобы MyDate оставался датой javascript и правильно интерпретировался с помощью управления вводом?

См. раздел 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>
4b9b3361

Ответ 1

В то время как ответ @amakhrov будет работать (и был бы даже лучше, если бы он использовался для записи, который можно было бы вычислить, например, в стиле @Stijn), я решил сделать это с помощью Custom Bindings.

Главное преимущество этого - повторное использование - мне просто нужно использовать data-bind="datePicker : MyDate", где бы я ни хотел привязать это. Я также могу изменить другие свойства входного элемента, чтобы это было действительно полезно, если привязка к сложному jQuery ( и другие).

(Читайте здесь, чтобы узнать больше про/против о 3 вариантах, чтобы делать такие вещи)

HTML

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

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);

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

Ответ 2

Вы можете использовать вычисленную vartiable для объекта date в вашей модели:

В html:

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

В коде:

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)

См. демонстрацию: http://jsfiddle.net/gcAXB/1/

Ответ 3

Здесь решение, которое работает для меня с последними нокаутами, основано на ссылке ниже и изменено, чтобы иметь пользовательскую функцию инициализации для обработки обновлений ko.computed-свойств по мере изменения значения даты.

Обратите внимание, что 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>

ОБНАРУЖЕНИЕ И ФОРМИРОВАНИЕ ДАННЫХ ИСПОЛЬЗОВАНИЕ KNOCKOUT И MOMENT JS

Ответ 4

В наши дни намного проще с 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

В html вы можете связать его с

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

И отобразите его в формате

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

Не нужно создавать пользовательские привязки, и вы можете использовать прокладку для старых браузеров.

Ответ 5

Так же, как это пользовательское связывание, но с помощью 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");
    }
};

Ответ 6

Основанный на ответе Райана выше, это работает немного лучше с новыми виджетами 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;
        }
    }
};

Ответ 7

Из HTML 5 - Форматирование даты ввода типа на iOS

В игре есть два формата:

  • отображаемый формат
  • внутренний формат, который подвергается JavaScript и отправляется на сервер

Вы не можете изменить формат отображения. Это в браузере, чтобы решить как дата представляется пользователю (на практике она определяется system locale).

Вы также не можете изменить внутренний формат. Это всегда ISO8601, независимо от браузера/локали.

Вам придется предварительно заполнить его этим конкретным форматом, и вы можете добавить вычисленный наблюдаемый для его анализа в объект Date, чтобы его можно было прочитать в других местах вашего приложения.

Если вы также хотите записать в него JS, вы можете настроить записываемый вычисленный наблюдаемый и проанализировать ввод, чтобы увидеть, строка из поля ввода или объект Date из вашего JS.

Ответ 8

Это сработало для меня

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"/>