【问题标题】:Knockout checkbox change event sends old value剔除复选框更改事件发送旧值
【发布时间】:2012-07-02 13:46:44
【问题描述】:

我遇到了敲除“已检查”绑定的问题。似乎复选框处的“更改”事件在更新之前返回旧值(因此,如果未选中,它将返回 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 被更改时,它总是发送旧值、触发方法,然后更改值。有没有办法解决这个问题?

【问题讨论】:

  • 您的代码有问题。 ShowOpenedIsUpdated 都不是 ko.observables(可能这就是为什么你总是得到旧值的原因)。这段代码怎么能工作? CategoryChange 应该抛出异常。
  • @freakish 你说得对,我最初创建这篇文章时犯了一个错误。但是您指出的错误仍然不是问题。
  • 喂,还是错过了这个:this.ShowOpened = ko.observable(ShowOpened); 和这个:pCategory.ShowOpened()。我必须说,你在写这篇文章时犯了很多错误......

标签: knockout.js knockout-2.0


【解决方案1】:

由于您坚持说缺少ko.observables 不是问题,因此我仔细研究了它。看来,你是对的! change 事件设置实际值之前触发。恐怕我不知道这是什么原因。

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

<input type="checkbox" data-bind="checked: ShowOpened, click: $root.CategoryChange" />

请记住,您必须明确地将 return true; 放在 click 事件处理程序的末尾。否则新值不会设置为复选框。

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

this.ShowOpened = ko.observable(ShowOpened);
this.ShowOpened.subscribe(function(newValue) {
    /* Do something when ShowOpened changes.
       newValue variable holds the new value, obviously. :) */
});

【讨论】:

  • 很好,点击事件有效。我试过了,只是忘了返回true,复选框从未被选中/取消选中。谢谢。
  • 我遇到了完全相同的问题,即 IE 无法识别 change 事件。 Grr.
  • 完美运行!谢谢。 “回归真”;是使其正常工作的关键!
  • 即使我按下空格键并且复选框有焦点,点击事件也被触发了。
  • 在阅读此答案之前我使用了两个复选框,因为我没有返回 true。谢谢你的好解决方案。
【解决方案2】:

尝试使用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);

【讨论】:

    【解决方案3】:

    我也遇到了这个问题,但我无法使用订阅解决方案,因为我已经使用可以重置值的 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>
    

    我知道这不是最好的解决方案,但就我而言,我别无选择。

    【讨论】:

      猜你喜欢
      • 2013-08-03
      • 2011-01-07
      • 1970-01-01
      • 2014-07-08
      • 2010-10-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多