В моей модели представления у меня есть значение IsMale, которое имеет значение true или false.
В моем пользовательском интерфейсе я хочу привязать его к следующим переключателям:
<label>Male
<input type="radio" name="IsMale" value="true" data-bind="checked:IsMale"/>
</label>
<label>Female
<input type="radio" name="IsMale" value="false" data-bind="checked:IsMale"/>
</label>
Проблема, я думаю, в том, checked
что ожидается строка «истина» / «ложь». Итак, мой вопрос: как я могу получить эту двустороннюю привязку с этим пользовательским интерфейсом и моделью?
Ответы:
Один из вариантов - использовать записываемый вычисляемый наблюдаемый .
В этом случае, я думаю, что хороший вариант - сделать записываемый вычисляемый наблюдаемый «суб-наблюдаемым» вашего
IsMale
наблюдаемого. Ваша модель представления будет выглядеть так:var ViewModel = function() { this.IsMale = ko.observable(true); this.IsMale.ForEditing = ko.computed({ read: function() { return this.IsMale().toString(); }, write: function(newValue) { this.IsMale(newValue === "true"); }, owner: this }); };
Вы бы связали его в своем пользовательском интерфейсе, например:
<label>Male <input type="radio" name="IsMale" value="true" data-bind="checked:IsMale.ForEditing"/> </label> <label>Female <input type="radio" name="IsMale" value="false" data-bind="checked:IsMale.ForEditing"/> </label>
Пример: http://jsfiddle.net/rniemeyer/Pjdse/
источник
Я знаю, что это старый поток, но у меня была та же проблема, и я обнаружил гораздо лучшее решение, которое, вероятно, было добавлено в нокаут после того, как на этот вопрос был официально дан ответ, поэтому я просто оставлю его для людей с той же проблемой.
В настоящее время нет необходимости в расширителях, пользовательских обработчиках привязок или вычислений. Просто укажите параметр «checkedValue», он будет использовать его вместо атрибута html 'value', и с его помощью вы можете передать любое значение javascript.
<input type="radio" name="a" data-bind="checked:IsChecked, checkedValue: true"/> <input type="radio" name="a" data-bind="checked:IsChecked, checkedValue: false"/>
Или же:
<input type="radio" name="b" data-bind="checked:Quantity, checkedValue: 1"/> <input type="radio" name="b" data-bind="checked:Quantity, checkedValue: 2"/> <input type="radio" name="b" data-bind="checked:Quantity, checkedValue: 3"/>
источник
value
привязку, а затемchecked
привязку (в этом порядке), но с 3.0 мне пришлось использоватьcheckedValue
привязку вместоvalue
привязки. (2) доvalue
версии 3.0 требовалось, чтобы привязка предшествовалаchecked
привязке для правильной работы, поэтому у меня есть ощущение, что в версии 3.0 все может работать лучше во всех сценариях, если вы поместитеcheckedValue
привязку передchecked
привязкой, например они показывают в документах .checked
сеттер (или , возможно , что - то зависит от него) вызывает ошибку - то правильный флажок не установленЭто работает для меня:
http://jsfiddle.net/zrBuL/291/
<label>Male <input type="radio" name="IsMale" value="1" data-bind="checked:IsMale"/> </label> <label>Female <input type="radio" name="IsMale" value="0" data-bind="checked:IsMale"/> </label>
источник
vm.IsMale(!!vm.+IsMale());
перед сериализацией json для отправки на сервер (в случае, если серверная сторона не может обработать его должным образом)ko.bindingHandlers['radiobuttonyesno'] = { 'init': function (element, valueAccessor, allBindingsAccessor) { var stateHandler = function (property, allBindingsAccessor, key, value, checkIfDifferent) { if (!property || !ko.isObservable(property)) { var propWriters = allBindingsAccessor()['_ko_property_writers']; if (propWriters && propWriters[key]) propWriters[key](value); } else if (ko.isWriteableObservable(property) && (!checkIfDifferent || property.peek() !== value)) { property(value); } }; var updateHandler = function () { var valueToWrite; if ((element.type == "radio") && (element.checked)) { valueToWrite = element.value; } else { return; // "radiobuttonyesno" binding only responds to selected radio buttons } valueToWrite = (valueToWrite === "True") ? true : false; var modelValue = valueAccessor(), unwrappedValue = ko.utils.unwrapObservable(modelValue); //can be true of false stateHandler(modelValue, allBindingsAccessor, 'checked', valueToWrite, true); }; ko.utils.registerEventHandler(element, "click", updateHandler); // IE 6 won't allow radio buttons to be selected unless they have a name if ((element.type == "radio") && !element.name) ko.bindingHandlers['uniqueName']['init'](element, function () { return true }); }, 'update': function (element, valueAccessor) { var value = ko.utils.unwrapObservable(valueAccessor()); value = value ? "True" : "False"; if (element.type == "radio") { element.checked = (element.value == value); } } };
Используйте это связующее вместо создания глупых вычисляемых наблюдаемых ко.
Пример:
<label>Male <input type="radio" name="IsMale" value="True" data-bind="radiobuttonyesno:IsMale"/> </label> <label>Female <input type="radio" name="IsMale" value="False" data-bind="radiobuttonyesno:IsMale"/> </label>
источник
Как только вы выясните, что начальное совпадение для переключателя хочет совпадать только со строкой и хочет установить значение в строку, остается просто преобразовать ваше начальное значение в строку. Мне пришлось бороться с этим с помощью значений Int.
После того, как вы настроили свои наблюдаемые, преобразуйте значение в строку, и KO сделает свое волшебство оттуда. Если вы отображаете отдельные строки, выполняйте преобразование в этих строках.
В примере кода я использую Json для сопоставления всей модели с помощью одной команды. Затем разрешите Razor вставить значение между кавычками для преобразования.
script type="text/javascript"> KoSetup.ViewModel = ko.mapping.fromJS(@Html.Raw(Json.Encode(Model))); KoSetup.ViewModel.ManifestEntered("@Model.ManifestEntered"); //Bool KoSetup.ViewModel.OrderStatusID("@Model.OrderStatusID"); //Int </script>
Я использую «Выгрузить все на экран» внизу моей веб-страницы во время разработки.
<h4>Debug</h4> <pre data-bind="text: ko.toJSON($data, null, 2)"></pre>
Вот значения данных, до
"OrderStatusID": 6, "ManifestEntered": true,
и, после
"OrderStatusID": "6", "ManifestEntered": "True",
В моем проекте мне не нужно было конвертировать Bools, потому что я могу использовать флажок, который не вызывает такого разочарования.
источник
Почему бы просто не просто истина и ложь вместо 1 и 0?
<label>Male <input type="radio" name="IsMale" value="true" data-bind="checked:IsMale"/> </label> <label>Female <input type="radio" name="IsMale" value="false" data-bind="checked:IsMale"/> </label>
источник
Вы также можете использовать расширитель, чтобы их было легко повторно использовать для большего количества наблюдаемых:
ko.extenders.boolForEditing = function (target, allowNull) { var result = ko.computed({ read: function () { var current = target(); var newValue = null; if (current === undefined || current === null || current === '') { if (!allowNull) { newValue = 'false'; } } else { newValue = current ? 'true' : 'false'; } return newValue; }, write: function (newValue) { var current = target(); var valueToWrite = null; if (newValue === undefined || newValue === null || newValue === '') { if (!allowNull) { valueToWrite = false; } } else { valueToWrite = newValue === 'true'; } // only write if it changed if (valueToWrite !== current) { target(valueToWrite); } else { if (newValue !== current) { target.notifySubscribers(valueToWrite); } } } }).extend({ notify: 'always' }); result(target()); return result; };
Затем используйте это так:
this.IsMale.forEditing = this.IsMale.extend({boolForEditing: true});
Предоставленный параметр
boolForEditing
указывает, может ли значение быть нулевым.См. Http://jsfiddle.net/G8qs9/1/
источник
После тщательного изучения старой версии knockout до 3.0, возможно, есть два лучших варианта
Создайте расширитель нокаута, например
ko.extenders["booleanValue"] = function (target) { target.formattedValue = ko.computed({ read: function () { if (target() === true) return "True"; else if (target() === false) return "False"; }, write: function (newValue) { if (newValue) { if (newValue === "False") target(false); else if (newValue === "True") target(true); } } }); target.formattedValue(target()); return target; };
Чтобы использовать удлинитель на вашей модели, сделайте что-то вроде следующего:
function Order() { this.wantsFries= ko.observable(false).extend({ booleanValue: null }); } <span>Do you want fries with that?</span> <label> <input type="radio" name="question" value="True" data-bind="value: wantsFries.formattedValue" /> Yes </label> <label> <input type="radio" name="question" value="False" data-bind="value: wantsFries.formattedValue" /> No </label>
источник: http://www.timlabonne.com/2013/02/building-a-knockout-js-extender-for-boolean-values/
источник