为什么我的 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”将不会得到验证。
- 双击 Item1 的 InputQTY 并将其更改为值 10。结果:Item1 得到验证。
- 双击 Item2 的 InputQTY 并将其更改为值 10。结果:Item2 未验证。
- 双击 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>
背景信息
我有一个包含三个项目详细信息的 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”将不会得到验证。
- 双击 Item1 的 InputQTY 并将其更改为值 10。结果:Item1 得到验证。
- 双击 Item2 的 InputQTY 并将其更改为值 10。结果:Item2 未验证。
- 双击 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>