2012-01-17 3 views
3

У меня есть случай, когда мне нужно, чтобы связать флажок и видимость другого DOM элемента к обратной Логическое свойство моего ViewModel:Как привязать флажок к обратному значению?

<input type="checkbox" data-bind="checked: needsReview"> Not Required 
<br> 
<div id="Some related text" data-bind="visible: needsReview"> other stuff here </div> 
var dataFromSever = { needsReview: true }; 

var theModel = function (jsonData) { 
    var self = this; 
    ko.mapping.fromJS(jsonData, {}, self); 
} 

ko.applyBindings(new theModel(dataFromSever)); 

У меня есть более чем одно свойство, как это в моя фактическая модель данных, поэтому я не хочу делать несколько полей ko.computed(). Я бы просто хотел связать с "checked: !needsReview()" или что-то в равной степени прост в обслуживании.

ответ

11

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

Вы можете сделать это в своей модели напрямую, используя удлинитель или добавив функцию к наблюдаемой базе (ko.observable.fn).

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

Вот привязка inverseChecked, которая вставляет записываемый счетчик, наблюдаемый между реальным наблюдаемым и привязкой. Затем он просто использует реальное проверочное связывание для выполнения своей работы.

ko.bindingHandlers.inverseChecked = { 
    init: function(element, valueAccessor, allBindingsAccessor) { 
     var value = valueAccessor(); 
     var interceptor = ko.computed({ 
          read: function() { 
           return !value(); 
          }, 
          write: function(newValue) { 
           value(!newValue); 
          }, 
          disposeWhenNodeIsRemoved: element 
         }); 

     var newValueAccessor = function() { return interceptor; }; 


     //keep a reference, so we can use in update function 
     ko.utils.domData.set(element, "newValueAccessor", newValueAccessor); 
     //call the real checked binding's init with the interceptor instead of our real observable 
     ko.bindingHandlers.checked.init(element, newValueAccessor, allBindingsAccessor); 
    }, 
    update: function(element, valueAccessor) { 
     //call the real checked binding's update with our interceptor instead of our real observable 
     ko.bindingHandlers.checked.update(element, ko.utils.domData.get(element, "newValueAccessor")); 
    } 
}; 

Вот пример: http://jsfiddle.net/rniemeyer/Kz4Tf/

Для вашего visible связывания вы можете сделать visible: !needsReview()

+3

Спасибо. Это похоже на то, что мне нужно. Просто кажется, что это должно быть проще, не так ли? Я посмотрю, не могу ли я это сделать сегодня утром ... – ShaneBlake

+0

То, что мне нужно. Большое спасибо ... – ShaneBlake

+0

Прохладный ответ, Право на. Но мне интересно, почему бы просто не использовать Radio Buttons? –

2

Я обычно делаю пользовательские bindingHandler в нокауте, который является инверсией visible:

ko.bindingHandlers['invisible'] = { 

    update: function(element, valueAccessor){ 
     var val = ko.utils.unwrapObservable(valueAccessor()); 

     ko.bindingHandlers['visible'].update(element, function() { return !val; });    
    } 
} 

Это позволяет аккуратно заботиться о потребностях, как вы описали, не загромождая свое data-bind заявления с уродливой !val()

+0

Спасибо, но это будет заботиться только о «видимой» привязке. Это не устранит проблему с привязкой к флажку. – ShaneBlake

+0

Yep - Райан избил меня до удара по другой половине вопроса. Добавление обоих этих обработчиков привязки к вашему проекту должно позволить вам немного очистить ваши инструкции привязки. – ericb

0

Я предпочитаю более общий и универсальный способ переворачивания наблюдаемую/вычисленное значение (которое не зависит от любое специфическое связывание):

/** 
* A small handy observable/computed function that wraps around the inverse of it's boolean value. 
* @author Nir Azuelos 
* @returns {Function} 
*/ 
ko.observable.fn.inverse = ko.computed.fn.inverse = function() { 
    return ko.pureComputed(function() { return !this(); }, this); 
}; 

Использование:

<div data-bind="visible: myObservable.inverse()">