问题
I'd like to use a property on my ViewModel to toggle which icon to display without creating a separate computed property of the inverse. Is this possible?
<tbody data-bind="foreach: periods">
<tr>
<td>
<i class="icon-search" data-bind="visible: !charted, click: $parent.pie_it"></i>
<i class="icon-remove" data-bind="visible: charted, click: $parent.pie_it"></i>
</td>
</tr>
</tbody>
My ViewModel has a property periods which is an array of month, like this:
var month = function() {
this.charted = ko.observable(false);
};
回答1:
When using an observable in an expression you need to access it as a function like:
visible: !charted()
回答2:
I agree with John Papa's comment that there should be a built-in hidden binding. There are two benefits to a dedicated hidden binding:
- Simpler syntax, ie.
hidden: chartedinstead ofvisible: !charted(). - Less resources, since Knockout can observe the observable
charteddirectly, rather than creating acomputedto observe!charted().
It's simple enough to create a hidden binding, though, like this:
ko.bindingHandlers.hidden = {
update: function(element, valueAccessor) {
ko.bindingHandlers.visible.update(element, function() {
return !ko.utils.unwrapObservable(valueAccessor());
});
}
};
You can use it just like the built-in visible binding:
<i class="icon-search" data-bind="hidden: charted, click: $parent.pie_it"></i>
<i class="icon-remove" data-bind="visible: charted, click: $parent.pie_it"></i>
回答3:
It's little confusing, as you have to do
visible:!showMe()
so, i did
<span data-bind="visible:showMe">Show</span>
<span data-bind="visible:!showMe()">Hide</span>
<label><input type="checkbox" data-bind="checked:showMe"/>toggle</label>
my model is
var myModel={
showMe:ko.observable(true)
}
ko.applyBindings(myModel);
check in fiddle http://jsfiddle.net/khanSharp/bgdbm/
回答4:
You could use my switch/case binding, which includes case.visible and casenot.visible.
<tbody data-bind="foreach: periods">
<tr>
<td data-bind="switch: true">
<i class="icon-search" data-bind="case.visible: $else, click: $parent.pie_it"></i>
<i class="icon-remove" data-bind="case.visible: charted, click: $parent.pie_it"></i>
</td>
</tr>
</tbody>
You could also have it as
<i class="icon-search" data-bind="casenot.visible: charted, click: $parent.pie_it"></i>
<i class="icon-remove" data-bind="case.visible: $else, click: $parent.pie_it"></i>
回答5:
In order to make the binding aware of changes to the property, I copied the visible binding handler and inverted it:
ko.bindingHandlers.hidden = {
update: function (element, valueAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor());
var isCurrentlyHidden = !(element.style.display == "");
if (value && !isCurrentlyHidden)
element.style.display = "none";
else if ((!value) && isCurrentlyHidden)
element.style.display = "";
}
};
回答6:
Disclaimer: this solution is for entertainment purposes only.
ko.extenders.not = function (target) {
target.not = ko.computed(function () {
return !target();
});
};
self.foo = ko.observable(true).extend({ not: null });
<div data-bind="text: foo"></div> <!-- true -->
<div data-bind="text: foo.not"></div> <!-- false -->
<!-- unfortunately I can't think of a way to be able to use:
text: foo...not
-->
回答7:
I was having the same issue about how to use an opposite of a boolean observable. I have found an easy solution:
var ViewModel = function () {
var self = this;
// When program start, this is set to FALSE
self.isSearchContentValid = ko.observable(false);
self.gatherPlacesData = function () {
// When user click a button, the value become TRUE
self.isSearchContentValid(true);
};
Now on your HTML you should do this
<p data-bind = "visible:isSearchContentValid() === false"> Text 1</p>
<p data-bind = "visible:isSearchContentValid"> Text 2</p>
When the program starts only "Text1" is visible because "false===false is TRUE" and Text2 is not visible.
Lets say we have a button which invokes the gatherPlacesData on click event. Now Text1 won't be visible because "true === false is FALSE" and Text 2 only be visible.
Another possible solution could be using computed observable but, I think is a overcomplicated solution for a so simple problem.
回答8:
Also can use hidden like this:
<div data-bind="hidden: isString">
<input type="text" class="form-control" data-bind="value: settingValue" />
</div>
来源:https://stackoverflow.com/questions/10114472/is-it-possible-to-data-bind-visible-to-the-negation-of-a-boolean-viewmodel