Knockout复选框更改事件发送旧值

时间:2012-07-02 13:46:45

标签: knockout.js knockout-2.0

我遇到了敲门“检查”绑定的问题。似乎复选框中的“更改”事件在更新之前返回旧值(因此如果未选中它将返回false)。我不认为我可以订阅这个值,因为我把它放在了对象中。

<tbody data-bind="foreach: Categories">
                <tr>
                    <td><input type="checkbox" data-bind="checked: ShowOpened, event: { change: $root.CategoryChange }" /></td>
                </tr>
            </tbody>
<script type="text/javascript">
var Category = function (Id, Name, Order, ShowOpened) {
    this.Id = Id;
    this.Name = Name;
    this.Order = Order;
    this.ShowOpened = ShowOpened;
    this.IsUpdated = ko.observable(false);

    this.OldOrder = Order;
    this.OldShowOpened = ShowOpened;
};
var ViewModel = {
    Categories: ko.observableArray([]),
    CategoryChange: function(pCategory) {
        if(pCategory.Order != pCategory.OldOrder || pCategory.ShowOpened != pCategory.OldShowOpened)
            pCategory.IsUpdated(true);
        else
            pCategory.IsUpdated(false);
    }
};
ko.applyBindings(ViewModel);
</script>

所以在这个例子中我有ShowOpened复选框,可以触发CategoryChange方法,它将改变对象内部的变量(我稍后需要知道更新了什么对象)。但是当更改chechbox时,它总是发送旧值,触发方法,然后更改值。有什么方法可以解决这个问题吗?

3 个答案:

答案 0 :(得分:62)

既然你坚持认为缺乏ko.observables并不是问题,那我就更贴近了。看来,你是对的! {<1}}事件在设置实际值之前触发。我担心我不知道原因。

但有一种简单的方法可以解决此问题:只需将change事件更改为change事件:

click

请记住,您必须明确地将<input type="checkbox" data-bind="checked: ShowOpened, click: $root.CategoryChange" /> 放在return true;事件处理程序的末尾。否则,新值将不会设置为复选框。

如果您不想使用click事件,那么您可以采用其他方式。订阅click的更改:

ShowOpened

答案 1 :(得分:6)

尝试使用subscribe而不是事件绑定。这应该现在可以使用

<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);

或者作为替代方案(在我看来是更好的解决方案),您可以使用dependentObservable,现在称为computed。这是它的样子

<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);

答案 2 :(得分:0)

我也有这个问题,但是我无法使用订阅解决方案,因为我已经使用可能重置值的ajax请求订阅了相同的字段。当您更改代码时,代码将保持循环。所以我添加了以下解决方法(它很难看,但它有效)。

$("input[type='radio'], input[type='checkbox']", element).on("change", function (e, data) {
    setTimeout(function () {
        $(this).trigger("afterChange", data);
    }.bind(this), 10);
}); 

然后,在听取改变时,我会听取afterChange事件。

<div data-bind="foreach: answerList">
    <input type="checkbox" data-bind="event: { afterChange: $root.sendSelectedAnswer($data) }"/>
</div>

我知道这不是最好的解决方案,但在我的情况下,我别无选择。