Knockoutjs databind с jquery-ui datepicker

Я использую jQuery UI datepicker. Введенное им поле ввода HTML в настоящее время подключено к KnockoutJS в качестве dependObservable, но когда его значение задано в viewmodel, datepicker теряет свой формат.

Как мне это сделать и не потерять формат? Я бы хотел, чтобы viewModel не знал, что это jQuery datepicker.

Ответ 1

Вы можете написать настраиваемую привязку, которая устанавливает дату в поле, используя API datepicker, а также устанавливает значение вашего наблюдаемого, правильно прочитав дату.

Пользовательская привязка может выглядеть так:

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/

Ответ 2

Мне пришлось внести небольшое изменение в код RP Niemeyer для работы в моем коде с использованием параметра dateFormat, заменив

$(element).datepicker("getDate")

С

$(element).val()

Таким образом, форматированная версия даты была правильно размещена под капотом.

Ответ 3

Я использовал код RP Niemeyer, помеченный как ответ выше, но поскольку я его использовал, я внес несколько небольших изменений в него. Я думал, что отправлю сюда. Может быть, это поможет другим. Это почти то же самое, единственное отличие состоит в том, что если элемент имеет значение при загрузке страницы, то он сохранит свое значение. Кроме того, я сделал переменную $elem так, что будет меньше обработки $(element), которую должен выполнить jQuery.

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

Ответ 4

Образцы datepicker выше изменяют формат даты в модели view из Формат WCF в формат даты JavaScript, когда пользователь выбирает новую дату от элемента управления datepicker.

В моем случае я передавал дату обратно в службу WCF и не принимал десериализованную дату JavaScript, ей нужна дата в формате WCF. Я изменил приведенный выше script так, чтобы он сохранял дату в viewmodel в формате 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);
        }
    }
};

Ответ 5

Вот что сработало для моего конкретного набора обстоятельств. Я запускаю достаточно новую версию MVC, которую наборщик данных по умолчанию datetime отображает в ISO 8601 (см. В кошмар, который является датами JSON. Кроме того, JSON.NET и веб-API ASP.NET). Мои привязки не не записываются непосредственно в подборщик даты, а вместо этого в атрибут "значение" тега ввода.

Кроме того, отметим, что я использую 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, чтобы включить datepicker:

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

Ответ 6

Одним из решений является форматирование даты самостоятельно в функции dependObservable. Поэтому вы должны возвращать что-то вроде return viewModel.someOtherObservable() в функции. Отформатируйте возвращаемое значение.

Если вы включите свой код, я могу объяснить больше.

Ответ 7

Форматирование даты (в мм/дд/гггг) внутри зависимогоОбсервива - это именно то, что мне было интересно, как это сделать. Я напишу немного своего кода, если вы можете помочь, Питер Мортенсен и/или 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 - технологияdetail.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", но он не влияет на отображаемое начальное значение.

Мне удалось отформатировать его с помощью момента, и он отлично работает для отображения текущего значения базы данных, но, похоже, он прерывает привязку к наблюдаемому, потому что он больше не будет обновлять SAVE.

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