为什么我的 Knockoutjs Computed Observable 在我的 Observable 数组排序时不起作用?

Why is my Knockoutjs Computed Observable Not Working when my Observable Array is being Sorted?

背景信息

我有一个包含三个项目详细信息的 Observable 数组。每个项目详细信息具有以下属性;项目、组、总数量和输入数量。当用户输入输入数量并且它与总数量匹配时,该项目将被“验证”,这意味着它变灰并移至列表底部。这是使用 HTML 中的 JavaScript 排序函数完成的(参见下面的代码片段)

    <tbody data-bind="foreach: ItemsByGroupArray().sort(function (l, r) { return l.Verified() == r.Verified() ? 0 : (l.Verified() < r.Verified() ? -1 : 1 ) } )">   
        <tr data-bind="css: {'verified-item': Verified }">
            <td data-bind="text: $index() + 1"></td>
            <td data-bind="text: ITEM"></td>
            <td data-bind="text: GROUP"></td>
            <td>
                <input type="number" data-bind="value: InputQTY, valueUpdate: ['afterkeydown', 'input']"
                       size="4" min="0" max="9999" step="1" style=" width:50px; padding:0px; margin:0px">                        
            </td>
            <td data-bind="text: TotalQTY"></td>
        </tr>
    </tbody>

在对数组进行排序时,会处理一个计算的可观察对象。此 observable 用于检查 ItemsByGroupArray 中的每个 InputQTY 是否与 TotalQTY 匹配。如果是,则项目详细信息将标记为已验证。 (见片段)

self.ITEMInputQTYs = ko.computed(function () {
    return ko.utils.arrayForEach(self.ItemsByGroupArray(), function (item) {
        if (item.InputQTY() == item.TotalQTY()) {
            item.Verified(true);
        } else {
            item.Verified(false);
        }
    });
});

片段所在的可执行代码:

var itemDetail = function (item, group, iQty, tQty, verified) {
    var self = this;
    self.ITEM = ko.observable(item);
    self.GROUP = ko.observable(group);
    self.InputQTY = ko.observable(iQty);
    self.TotalQTY = ko.observable(tQty);
    self.Verified = ko.observable(verified);
};

// The core viewmodel that handles much of the processing logic.
var myViewModel = function () {
    var self = this;

    self.ItemsByGroupArray = ko.observableArray([]);

    self.ITEMInputQTYs = ko.computed(function () {
        return ko.utils.arrayForEach(self.ItemsByGroupArray(), function (item) {
            if (item.InputQTY() == item.TotalQTY()) {
                item.Verified(true);
            } else {
                item.Verified(false);
            }
        });
    });
    
    self.AddItems = function() {
        var newItemData = new itemDetail("ITEM1", "GROUP1", 0, 10, false);
        var newItemData2 = new itemDetail("ITEM2", "GROUP1", 0, 10, false);
        var newItemData3 = new itemDetail("ITEM3", "GROUP1", 0, 10, false);

        self.ItemsByGroupArray.push(newItemData);
        self.ItemsByGroupArray.push(newItemData2);
        self.ItemsByGroupArray.push(newItemData3);        
    };
    
    self.AddItems();
};

ko.applyBindings(new myViewModel());
.verified-item
{
    text-decoration: line-through;
    background: Gray;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<table style="width:90%; margin-left: auto; margin-right: auto;">
    <thead>
        <tr>
            <th></th>
            <th>ITEM</th>
            <th>GROUP</th>
            <th>InputQty</th>
            <th>TotalQty</th>
        </tr>
    </thead>
    
    <!--    <tbody data-bind="foreach: ItemsByGroupArray()">    -->
        
    <tbody data-bind="foreach: ItemsByGroupArray().sort(function (l, r) { return l.Verified() == r.Verified() ? 0 : (l.Verified() < r.Verified() ? -1 : 1 ) } )">
    
        <tr data-bind="css: {'verified-item': Verified }">
            <td data-bind="text: $index() + 1"></td>
            <td data-bind="text: ITEM"></td>
            <td data-bind="text: GROUP"></td>
            <td>
                <input type="number" data-bind="value: InputQTY, valueUpdate: ['afterkeydown', 'input']"
                       size="4" min="0" max="9999" step="1" style=" width:50px; padding:0px; margin:0px">                        
            </td>
            <td data-bind="text: TotalQTY"></td>
        </tr>
    </tbody>
</table>

问题

这里的问题是,如果您 运行 fiddle 并执行以下步骤,“项目 3”将不会得到验证。

  1. 双击 Item1 的 InputQTY 并将其更改为值 10。结果:Item1 得到验证。
  2. 双击 Item2 的 InputQTY 并将其更改为值 10。结果:Item2 未验证。
  3. 双击 Item3 的 InputQTY 并将其更改为值 10。结果:Item2 得到验证,但 Item3 没有。

我的问题

为什么第三项没有按预期计算,我该如何解决这个问题?另外,这是否可能是 Knockoutjs 代码中的错误?

提前感谢您的任何回复!

由于 knockout 获取其初始计算变量的方式,这一次有效。但实际上需要的是在项目的 属性 发生变化时触发 observableArray。我已在解决您的问题的 AddItem 部分添加了附加代码。

var itemDetail = function(item, group, iQty, tQty, verified) {
  var self = this;
  self.ITEM = ko.observable(item);
  self.GROUP = ko.observable(group);
  self.InputQTY = ko.observable(iQty);
  self.TotalQTY = ko.observable(tQty);
  self.Verified = ko.observable(verified);
};

// The core viewmodel that handles much of the processing logic.
var myViewModel = function() {
  var self = this;

  self.ItemsByGroupArray = ko.observableArray([]);

  self.ITEMInputQTYs = ko.computed(function() {
    return ko.utils.arrayForEach(self.ItemsByGroupArray(), function(item) {
      if (item.InputQTY() == item.TotalQTY()) {
        item.Verified(true);
      } else {
        item.Verified(false);
      }
    });
  });

  self.AddItems = function() {
    var newItemData = new itemDetail("ITEM1", "GROUP1", 0, 10, false);
    var newItemData2 = new itemDetail("ITEM2", "GROUP1", 0, 10, false);
    var newItemData3 = new itemDetail("ITEM3", "GROUP1", 0, 10, false);

    self.ItemsByGroupArray.push(newItemData);
    self.ItemsByGroupArray.push(newItemData2);
    self.ItemsByGroupArray.push(newItemData3);

    ko.utils.arrayForEach(self.ItemsByGroupArray(), function(item) {
      item.InputQTY.subscribe(function(val) {
        self.ItemsByGroupArray.valueHasMutated();
      });
    });
  };

  self.AddItems();
};

ko.applyBindings(new myViewModel());
.verified-item {
  text-decoration: line-through;
  background: Gray;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<table style="width:90%; margin-left: auto; margin-right: auto;">
  <thead>
    <tr>
      <th></th>
      <th>ITEM</th>
      <th>GROUP</th>
      <th>InputQty</th>
      <th>TotalQty</th>
    </tr>
  </thead>

  <!--    <tbody data-bind="foreach: ItemsByGroupArray()">    -->

  <tbody data-bind="foreach: ItemsByGroupArray().sort(function (l, r) { return l.Verified() == r.Verified() ? 0 : (l.Verified() < r.Verified() ? -1 : 1 ) } )">

    <tr data-bind="css: {'verified-item': Verified }">
      <td data-bind="text: $index() + 1"></td>
      <td data-bind="text: ITEM"></td>
      <td data-bind="text: GROUP"></td>
      <td>
        <input type="number" data-bind="value: InputQTY, valueUpdate: ['afterkeydown', 'input']" size="4" min="0" max="9999" step="1" style=" width:50px; padding:0px; margin:0px">
      </td>
      <td data-bind="text: TotalQTY"></td>
    </tr>
  </tbody>
</table>