knockoutjs привязка данных с помощью jquery-ui datepicker

Я использую JQuery UI DatePicker. Поле ввода HTML позади него в настоящее время подключено к KnockoutJS как зависящий от объекта, но когда его значение задается в модели представления, средство выбора даты теряет свой формат.

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

7 ответов

Решение

Вы можете написать пользовательскую привязку, которая устанавливает дату в поле, используя 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/

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

$(element).datepicker("getDate")

С

$(element).val()

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

Я использовал код 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);
        }
    }
};

Вот то, что сработало для моих конкретных обстоятельств. Я использую достаточно новую версию MVC, которую сериализатор даты и времени по умолчанию отображает при ISO 8601 (см. "Кошмар, который является датами JSON. Плюс, JSON.NET и 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" });
});

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

В моем случае я передавал дату обратно службе 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);
        }
    }
};

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

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

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

В текстовом поле отображается дата, которая выглядит следующим образом: ср 29 января 19:00:00 EST 2014, но я хочу, чтобы она просто отображалась: 29.01.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')" />
Другие вопросы по тегам