MVC 4 — Выбивание пользовательской привязки и формата даты

#asp.net-mvc #date #knockout.js #format

#asp.net-mvc #Дата #knockout.js #формат

Вопрос:

Я использую Asp.Net MVC 4 и Нокаут в форме.

У меня есть ввод даты, который я хочу отформатировать.

В итоге я получил это решение: http://jason-mitchell.com/web-development/binding-dates-using-knockout-moment-js /

Моя проблема в том, что когда я отправляю форму, у меня нет даты, заполненной в опубликованном JSON.

Я думаю, что проблема находится в пользовательском обработчике, но я не могу выяснить: (Событие обновления срабатывает только один раз при загрузке.

Просмотр кода

 @Html.TextBoxFor(Function(model) model.EndDate, New With {.data_bind = "date: EndDate"})
  

Пользовательский код привязки

 ko.bindingHandlers.date = {   
    update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        var value = valueAccessor();
        var valueUnwrapped = ko.utils.unwrapObservable(value);
        var allBindings = allBindingsAccessor();

        // Date formats: http://momentjs.com/docs/#/displaying/format/
        var pattern = allBindings.format || 'L';

        var output = "";
        if (valueUnwrapped !== null amp;amp; valueUnwrapped !== undefined amp;amp; valueUnwrapped.length > 0) {
            output = moment(valueUnwrapped).format(pattern);
        }

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

Код привязки ko

 var viewModel = ko.mapping.fromJS(@Html.Raw(Model.ToJson()));
ko.applyBindings(viewModel);
  

Примечание: формат даты работает так, как ожидалось.

Что я делаю не так? 🙁

Ответ №1:

Не видя вашей ViewModel, я могу только строить предположения. В вашем коде вы привязываете конечную дату непосредственно к текстовому полю:

 @Html.TextBoxFor(Function(model) model.EndDate, New With {.data_bind = "date: EndDate"})
  

Ваша наблюдаемая конечная дата ничего не знает об этом значении. Поэтому, если ваша наблюдаемая конечная дата выглядит примерно так в вашей ViewModel:

 this.EndDate = ko.observable();
  

Тогда он не знает о значении, которое было привязано непосредственно к текстовому полю вашим ASP.NET Код MVC. Поэтому, когда вы применяете свои привязки KO, значение конечной даты, которое было привязано непосредственно к текстовому полю, уничтожается. Если это так, вы можете либо (1) инициализировать наблюдаемую конечную дату непосредственно из значения, привязанного к модели сервера, либо (2) инициализировать наблюдаемую конечную дату косвенно, используя пользовательскую привязку KO, которая инициализирует наблюдаемую конечную дату из значения, которое было привязано непосредственно к текстовому полю.

Пример 1

В этом примере предполагается, что JavaScript находится непосредственно в вашем представлении. Если ваш JavaScript находится в отдельном файле (как это обычно бывает), вам придется передать данные модели в вашу ViewModel, используя другой метод, такой как сериализация JSON на клиенте, прежде чем привязывать вашу ViewModel.

 this.EndDate = ko.observable('@Model.EndDate.ToString()');
  

Пример 2

В этом примере важен последовательный порядок параметров привязки KO. Новая пользовательская привязка должна быть первой привязкой, чтобы это работало правильно:

 @Html.TextBoxFor(Function(model) model.EndDate, New With {.data_bind = "initInputFromView: EndDate, date: EndDate"})
  

И вот код для пользовательской привязки KO:

 ko.bindingHandlers.initInputFromView = {
    init: function (element, valueAccessor) {
        // reads the value stored in the <input> value attribute and initializes the observable with that value
        valueAccessor()(element.value);
    }
};
  

Комментарии:

1. Фактически, я заполняю ko ViewModel этой строкой: var ViewModel = ko.mapping.fromJS(@Html.Raw(Model. toJSON())); @Html.Raw(Модель. toJSON())); дайте мне этот Json для конечной даты: «{«Конечная дата»:»2014-12-31T00:00:00″}» С предупреждением (ViewModel. EndDate()); сразу после изменения ViewModel = ko.mapping.fromJS(@Html.Raw(Model. toJSON())); Я получаю «2014-12-31T00:00:00». Поэтому я думаю, что он знает начальное значение. Привязка работает просто отлично, без какой-либо другой привязки «дата»? :/

Ответ №2:

Наконец, я нашел решение!

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

 ko.bindingHandlers.date = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {       
        ko.bindingHandlers.value.init(element, valueAccessor, 
             allBindingsAccessor, viewModel, bindingContext);

        var value = valueAccessor();
        var valueUnwrapped = ko.utils.unwrapObservable(value);
        var allBindings = allBindingsAccessor();
        // Date formats: http://momentjs.com/docs/#/displaying/format/
        var pattern = allBindings.format || 'L';

        var output = valueUnwrapped;
        if (valueUnwrapped !== null amp;amp; valueUnwrapped !== undefined amp;amp; valueUnwrapped.length > 0) {
            output = moment(valueUnwrapped).format(pattern);
        }

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

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