如何使用敲除数据和 "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>