I\'m having a problem with knockout \"checked\" binding. It seems that \"change\" event at checkbox return old value, before it is updated(so if it was unchecked it will return
Since you persisted on stating that the lack of ko.observables
is not an issue, I've looked at it closer. It seems, that you are correct! The change
event is fired before the actual value is set. I'm afraid I do not know the reason for this.
But there is an easy way to fix this: just change change
event to click
event:
<input type="checkbox" data-bind="checked: ShowOpened, click: $root.CategoryChange" />
Remember, that you have to explicitly put return true;
at the end of click
event handler. Otherwise the new value won't be set to checkbox.
If you do not want to use click
event, then you can do it the other way. Subscribe to changes of ShowOpened
:
this.ShowOpened = ko.observable(ShowOpened);
this.ShowOpened.subscribe(function(newValue) {
/* Do something when ShowOpened changes.
newValue variable holds the new value, obviously. :) */
});
I also had this issue, but i couldn't use the subscribe solution because i was already subscribed to the same field with a ajax request that could reset the value. The code would then stay in a loop when you changed it. So i added the following workaround (its ugly but it works).
$("input[type='radio'], input[type='checkbox']", element).on("change", function (e, data) {
setTimeout(function () {
$(this).trigger("afterChange", data);
}.bind(this), 10);
});
Then instead on listening to the change i would listen to the afterChange event.
<div data-bind="foreach: answerList">
<input type="checkbox" data-bind="event: { afterChange: $root.sendSelectedAnswer($data) }"/>
</div>
I know its not the best solution, but in my case i had no other option.
Try using subscribe
instead of event binding. This should work now
<table>
<tbody data-bind="foreach: Categories">
<tr>
<td><input type="checkbox" data-bind="checked: ShowOpened" /></td>
</tr>
</tbody>
<table>
var Category = function (Id, Name, Order, ShowOpened) {
this.Id = Id;
this.Name = Name;
this.Order = Order;
this.ShowOpened = ko.observable(ShowOpened);
this.IsUpdated = false;
this.OldOrder = Order;
this.OldShowOpened = ShowOpened;
this.ShowOpened.subscribe(function (newShowOpened) {
if(this.Order != this.OldOrder || this.ShowOpened() != this.OldShowOpened)
this.IsUpdated = true;
else
this.IsUpdated = false;
}, this);
};
var ViewModel = {
Categories: ko.observableArray([])
};
ko.applyBindings(ViewModel);
Or as alternative (and in my opinion a better solution) you can use dependentObservable
, now called computed
. Here's how it would look like
<table>
<tbody data-bind="foreach: Categories">
<tr>
<td>
<input type="checkbox" data-bind="checked: ShowOpened" />
<span data-bind="text: IsUpdated"></span>
</td>
</tr>
</tbody>
</table>
var Category = function (Id, Name, Order, ShowOpened) {
this.Id = Id;
this.Name = Name;
this.Order = Order;
this.ShowOpened = ko.observable(ShowOpened);
this.OldOrder = Order;
this.OldShowOpened = ShowOpened;
this.IsUpdated = ko.computed(function () {
return this.Order != this.OldOrder || this.ShowOpened() != this.OldShowOpened;
}, this);
};
var ViewModel = {
Categories: ko.observableArray([])
};
ko.applyBindings(ViewModel);