如何使用敲除数据和 "external" 数据过滤计算数据
How to filter data with computed using both knockout data and "external" data
背景: 我正在将遗留系统中的 javascript 逻辑移至剔除以获得更多结构并且不得不在未来。由于时间限制,我只能将部分代码移到每次部署之间的淘汰赛中。
问题:一些数据是由遗留代码生成的,一些数据是由淘汰赛生成的,我在创建淘汰赛逻辑来处理以下情况时遇到问题(请参阅下面的代码片段和相同代码的 JSFiddle link)。产品单选按钮不是由 knockout 生成的,但报价列表是。过滤报价列表的关键按钮可以像我希望的那样工作,但我还没有弄清楚如何只获得 Product 1 下列出的产品 1 的报价并且只提供产品 2 下列出的产品 2。有人可以帮忙吗?
我假设如果产品 headers 是从 knockout 视图模型中的数据生成的,我的问题就不会那么难解决,但如您所见,情况并非如此。
https://jsfiddle.net/b6er4wke/3/
function myViewModel() {
var self = this;
self.wrappedProducts = ko.observableArray();
self.availableOffers = ko.observableArray();
self.filterKey = ko.observable(1);
filteredItems = ko.computed(function() {
return ko.utils.arrayFilter(self.availableOffers(), function (offer) {
var isCorrectKey = offer.key == self.filterKey();
return (isCorrectKey);
});
});
self.filter = function(keyFilter) {
self.filterKey(keyFilter);
};
(function() {
// Products
self.wrappedProducts.push({"prod":"1"});
self.wrappedProducts.push({"prod":"2"});
// Offers
self.availableOffers.push({"name": "offer1", "key": "1", "prod": 1});
self.availableOffers.push({"name": "offer2", "key": "2", "prod": 1});
self.availableOffers.push({"name": "offer3", "key": "2", "prod": 2});
})();
}
var viewModel = new myViewModel();
ko.applyBindings(viewModel);
ul, h4 {margin-top: 0px; margin-bottom:0px;}
label {font-weight:bold;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<h4>All products</h4>
<ul data-bind="foreach: wrappedProducts">
<li data-bind="text: ko.toJSON($data)"></li>
</ul>
<h4>Available offers</h4>
<ul data-bind="foreach: availableOffers">
<li data-bind="text: ko.toJSON($data)"></li>
</ul>
<div>
<button data-bind="click: function() {filter(1);}">key1</button>
<button data-bind="click: function() {filter(2);}">key2</button>
filterKey = <span data-bind="text: filterKey"></span>
</div>
<hr>
<label for="prod1">Product 1</label>
<ul data-bind="foreach: filteredItems">
<li data-bind="text: ko.toJSON($data)"></li>
</ul>
<label for="prod2">Product 2</label>
<ul data-bind="foreach: filteredItems">
<li data-bind="text: ko.toJSON($data)"></li>
</ul>
好吧,您刚刚显示了相同计算的结果。所以,这就是为什么在 Prod 1 和 Prod 2 下你会得到相同的结果。如果您想按产品和密钥过滤,您需要两个计算函数来为您过滤。
您在 arrayFilter 中丢失的代码是这样的:
var isCorrectKey = offer.key == self.filterKey();
var isCorrectProduct = offer.prod == 2;
return isCorrectKey && isCorrectProduct;
您必须检查产品和密钥。
function myViewModel() {
var self = this;
self.wrappedProducts = ko.observableArray();
self.availableOffers = ko.observableArray();
self.filterKey = ko.observable(1);
filteredItemsKey1 = ko.computed(function () {
return ko.utils.arrayFilter(self.availableOffers(), function (offer) {
var isCorrectKey = offer.key == self.filterKey();
var isCorrectProduct = offer.prod == 1;
return isCorrectKey && isCorrectProduct;
});
});
filteredItemsKey2 = ko.computed(function () {
return ko.utils.arrayFilter(self.availableOffers(), function (offer) {
var isCorrectKey = offer.key == self.filterKey();
var isCorrectProduct = offer.prod == 2;
return isCorrectKey && isCorrectProduct;
});
});
self.filter = function(keyFilter) {
self.filterKey(keyFilter);
};
(function() {
// Products
self.wrappedProducts.push({"prod":"1"});
self.wrappedProducts.push({"prod":"2"});
// Offers
self.availableOffers.push({"name": "offer1", "key": "1", "prod": 1});
self.availableOffers.push({"name": "offer2", "key": "2", "prod": 1});
self.availableOffers.push({"name": "offer3", "key": "2", "prod": 2});
})();
}
var viewModel = new myViewModel();
ko.applyBindings(viewModel);
ul, h4 {margin-top: 0px; margin-bottom:0px;}
label {font-weight:bold;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<h4>All products</h4>
<ul data-bind="foreach: wrappedProducts">
<li data-bind="text: ko.toJSON($data)"></li>
</ul>
<h4>Available offers</h4>
<ul data-bind="foreach: availableOffers">
<li data-bind="text: ko.toJSON($data)"></li>
</ul>
<div>
<button data-bind="click: function() {filter(1);}">key1</button>
<button data-bind="click: function() {filter(2);}">key2</button>
filterKey = <span data-bind="text: filterKey"></span>
</div>
<hr>
<label for="prod1">Product 1</label>
<ul data-bind="foreach: filteredItemsKey1">
<li data-bind="text: ko.toJSON($data)"></li>
</ul>
<label for="prod2">Product 2</label>
<ul data-bind="foreach: filteredItemsKey2">
<li data-bind="text: ko.toJSON($data)"></li>
</ul>
Knockout 自动将您的绑定表达式包装在 computed
中,因此您实际上可以简单地使 filteredItems
成为一个常规函数并使用您要显示的产品作为参数调用它:
filteredItems = function filteredItems(product) {
return ko.utils.arrayFilter(self.availableOffers(), function (offer) {
return offer.key == self.filterKey() && offer.prod == product;
});
};
<label for="prod1">Product 1</label>
<ul data-bind="foreach: filteredItems(1)">
<li data-bind="text: ko.toJSON($data)"></li>
</ul>
<label for="prod2">Product 2</label>
<ul data-bind="foreach: filteredItems(2)">
<li data-bind="text: ko.toJSON($data)"></li>
</ul>
并且在 availableOffers
更改时仍然自动更新。
function myViewModel() {
var self = this;
self.wrappedProducts = ko.observableArray();
self.availableOffers = ko.observableArray();
self.filterKey = ko.observable(1);
filteredItems = function filteredItems(product) {
return ko.utils.arrayFilter(self.availableOffers(), function (offer) {
return offer.key == self.filterKey() && offer.prod == product;
});
};
self.filter = function(keyFilter) {
self.filterKey(keyFilter);
};
(function() {
// Products
self.wrappedProducts.push({"prod":"1"});
self.wrappedProducts.push({"prod":"2"});
// Offers
self.availableOffers.push({"name": "offer1", "key": "1", "prod": 1});
self.availableOffers.push({"name": "offer2", "key": "2", "prod": 1});
self.availableOffers.push({"name": "offer3", "key": "2", "prod": 2});
})();
}
var viewModel = new myViewModel();
ko.applyBindings(viewModel);
ul, h4 {margin-top: 0px; margin-bottom:0px;}
label {font-weight:bold;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<h4>All products</h4>
<ul data-bind="foreach: wrappedProducts">
<li data-bind="text: ko.toJSON($data)"></li>
</ul>
<h4>Available offers</h4>
<ul data-bind="foreach: availableOffers">
<li data-bind="text: ko.toJSON($data)"></li>
</ul>
<div>
<button data-bind="click: function() {filter(1);}">key1</button>
<button data-bind="click: function() {filter(2);}">key2</button>
filterKey = <span data-bind="text: filterKey"></span>
</div>
<hr>
<label for="prod1">Product 1</label>
<ul data-bind="foreach: filteredItems(1)">
<li data-bind="text: ko.toJSON($data)"></li>
</ul>
<label for="prod2">Product 2</label>
<ul data-bind="foreach: filteredItems(2)">
<li data-bind="text: ko.toJSON($data)"></li>
</ul>
背景: 我正在将遗留系统中的 javascript 逻辑移至剔除以获得更多结构并且不得不在未来。由于时间限制,我只能将部分代码移到每次部署之间的淘汰赛中。
问题:一些数据是由遗留代码生成的,一些数据是由淘汰赛生成的,我在创建淘汰赛逻辑来处理以下情况时遇到问题(请参阅下面的代码片段和相同代码的 JSFiddle link)。产品单选按钮不是由 knockout 生成的,但报价列表是。过滤报价列表的关键按钮可以像我希望的那样工作,但我还没有弄清楚如何只获得 Product 1 下列出的产品 1 的报价并且只提供产品 2 下列出的产品 2。有人可以帮忙吗?
我假设如果产品 headers 是从 knockout 视图模型中的数据生成的,我的问题就不会那么难解决,但如您所见,情况并非如此。
https://jsfiddle.net/b6er4wke/3/
function myViewModel() {
var self = this;
self.wrappedProducts = ko.observableArray();
self.availableOffers = ko.observableArray();
self.filterKey = ko.observable(1);
filteredItems = ko.computed(function() {
return ko.utils.arrayFilter(self.availableOffers(), function (offer) {
var isCorrectKey = offer.key == self.filterKey();
return (isCorrectKey);
});
});
self.filter = function(keyFilter) {
self.filterKey(keyFilter);
};
(function() {
// Products
self.wrappedProducts.push({"prod":"1"});
self.wrappedProducts.push({"prod":"2"});
// Offers
self.availableOffers.push({"name": "offer1", "key": "1", "prod": 1});
self.availableOffers.push({"name": "offer2", "key": "2", "prod": 1});
self.availableOffers.push({"name": "offer3", "key": "2", "prod": 2});
})();
}
var viewModel = new myViewModel();
ko.applyBindings(viewModel);
ul, h4 {margin-top: 0px; margin-bottom:0px;}
label {font-weight:bold;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<h4>All products</h4>
<ul data-bind="foreach: wrappedProducts">
<li data-bind="text: ko.toJSON($data)"></li>
</ul>
<h4>Available offers</h4>
<ul data-bind="foreach: availableOffers">
<li data-bind="text: ko.toJSON($data)"></li>
</ul>
<div>
<button data-bind="click: function() {filter(1);}">key1</button>
<button data-bind="click: function() {filter(2);}">key2</button>
filterKey = <span data-bind="text: filterKey"></span>
</div>
<hr>
<label for="prod1">Product 1</label>
<ul data-bind="foreach: filteredItems">
<li data-bind="text: ko.toJSON($data)"></li>
</ul>
<label for="prod2">Product 2</label>
<ul data-bind="foreach: filteredItems">
<li data-bind="text: ko.toJSON($data)"></li>
</ul>
好吧,您刚刚显示了相同计算的结果。所以,这就是为什么在 Prod 1 和 Prod 2 下你会得到相同的结果。如果您想按产品和密钥过滤,您需要两个计算函数来为您过滤。
您在 arrayFilter 中丢失的代码是这样的:
var isCorrectKey = offer.key == self.filterKey();
var isCorrectProduct = offer.prod == 2;
return isCorrectKey && isCorrectProduct;
您必须检查产品和密钥。
function myViewModel() {
var self = this;
self.wrappedProducts = ko.observableArray();
self.availableOffers = ko.observableArray();
self.filterKey = ko.observable(1);
filteredItemsKey1 = ko.computed(function () {
return ko.utils.arrayFilter(self.availableOffers(), function (offer) {
var isCorrectKey = offer.key == self.filterKey();
var isCorrectProduct = offer.prod == 1;
return isCorrectKey && isCorrectProduct;
});
});
filteredItemsKey2 = ko.computed(function () {
return ko.utils.arrayFilter(self.availableOffers(), function (offer) {
var isCorrectKey = offer.key == self.filterKey();
var isCorrectProduct = offer.prod == 2;
return isCorrectKey && isCorrectProduct;
});
});
self.filter = function(keyFilter) {
self.filterKey(keyFilter);
};
(function() {
// Products
self.wrappedProducts.push({"prod":"1"});
self.wrappedProducts.push({"prod":"2"});
// Offers
self.availableOffers.push({"name": "offer1", "key": "1", "prod": 1});
self.availableOffers.push({"name": "offer2", "key": "2", "prod": 1});
self.availableOffers.push({"name": "offer3", "key": "2", "prod": 2});
})();
}
var viewModel = new myViewModel();
ko.applyBindings(viewModel);
ul, h4 {margin-top: 0px; margin-bottom:0px;}
label {font-weight:bold;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<h4>All products</h4>
<ul data-bind="foreach: wrappedProducts">
<li data-bind="text: ko.toJSON($data)"></li>
</ul>
<h4>Available offers</h4>
<ul data-bind="foreach: availableOffers">
<li data-bind="text: ko.toJSON($data)"></li>
</ul>
<div>
<button data-bind="click: function() {filter(1);}">key1</button>
<button data-bind="click: function() {filter(2);}">key2</button>
filterKey = <span data-bind="text: filterKey"></span>
</div>
<hr>
<label for="prod1">Product 1</label>
<ul data-bind="foreach: filteredItemsKey1">
<li data-bind="text: ko.toJSON($data)"></li>
</ul>
<label for="prod2">Product 2</label>
<ul data-bind="foreach: filteredItemsKey2">
<li data-bind="text: ko.toJSON($data)"></li>
</ul>
Knockout 自动将您的绑定表达式包装在 computed
中,因此您实际上可以简单地使 filteredItems
成为一个常规函数并使用您要显示的产品作为参数调用它:
filteredItems = function filteredItems(product) {
return ko.utils.arrayFilter(self.availableOffers(), function (offer) {
return offer.key == self.filterKey() && offer.prod == product;
});
};
<label for="prod1">Product 1</label>
<ul data-bind="foreach: filteredItems(1)">
<li data-bind="text: ko.toJSON($data)"></li>
</ul>
<label for="prod2">Product 2</label>
<ul data-bind="foreach: filteredItems(2)">
<li data-bind="text: ko.toJSON($data)"></li>
</ul>
并且在 availableOffers
更改时仍然自动更新。
function myViewModel() {
var self = this;
self.wrappedProducts = ko.observableArray();
self.availableOffers = ko.observableArray();
self.filterKey = ko.observable(1);
filteredItems = function filteredItems(product) {
return ko.utils.arrayFilter(self.availableOffers(), function (offer) {
return offer.key == self.filterKey() && offer.prod == product;
});
};
self.filter = function(keyFilter) {
self.filterKey(keyFilter);
};
(function() {
// Products
self.wrappedProducts.push({"prod":"1"});
self.wrappedProducts.push({"prod":"2"});
// Offers
self.availableOffers.push({"name": "offer1", "key": "1", "prod": 1});
self.availableOffers.push({"name": "offer2", "key": "2", "prod": 1});
self.availableOffers.push({"name": "offer3", "key": "2", "prod": 2});
})();
}
var viewModel = new myViewModel();
ko.applyBindings(viewModel);
ul, h4 {margin-top: 0px; margin-bottom:0px;}
label {font-weight:bold;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<h4>All products</h4>
<ul data-bind="foreach: wrappedProducts">
<li data-bind="text: ko.toJSON($data)"></li>
</ul>
<h4>Available offers</h4>
<ul data-bind="foreach: availableOffers">
<li data-bind="text: ko.toJSON($data)"></li>
</ul>
<div>
<button data-bind="click: function() {filter(1);}">key1</button>
<button data-bind="click: function() {filter(2);}">key2</button>
filterKey = <span data-bind="text: filterKey"></span>
</div>
<hr>
<label for="prod1">Product 1</label>
<ul data-bind="foreach: filteredItems(1)">
<li data-bind="text: ko.toJSON($data)"></li>
</ul>
<label for="prod2">Product 2</label>
<ul data-bind="foreach: filteredItems(2)">
<li data-bind="text: ko.toJSON($data)"></li>
</ul>