按条件过滤observableArray

时间:2014-04-10 09:57:09

标签: knockout.js

我希望能够按特定条件过滤列表。我不想使用任何其他可观察的数组来存储过滤的项目,我想覆盖当前的数组。

HTML:

<div class='list'>
    <select data-bind="options: storedProceduresInDB1, value: filterStoredProceduresInDB1By, optionsText: 'Profile', optionsValue: 'Profile', optionsCaption: 'Filter by Profile'"></select>
    This will only filter the list below
    <p>Stored procedures:</p>
    <select multiple="multiple" height="5" data-bind="options:storedProceduresInDB1, optionsText: 'Name', selectedOptions:selectedStoredProceduresInDb1"></select>
</div>

代码:

var SProcsViewModel = function () {
    var self = this;
    self.storedProceduresInDB1 = ko.observableArray([{
        Name: "Sp1",
        Id: 1,
        Profile: 100
    }, {
        Name: "Sp2",
        Id: 2,
        Profile: 100
    }, {
        Name: "Sp3",
        Id: 3,
        Profile: 200
    }, {
        Name: "Sp4",
        Id: 4,
        Profile: 300
    }]);

    self.filterStoredProceduresInDB1By = ko.observable();
    self.selectedStoredProceduresInDb1 = ko.observableArray();
    self.selectedStoredProceduresInDb2 = ko.observableArray();

    return self;
};

ko.applyBindings(new SProcsViewModel());

JSFiddle

编辑:如果我选择配置文件100,我想用所有具有配置文件100的项目覆盖storedProceduresInDB1。正如您在JSFiddle2中看到的,我无法将数据绑定到其他数组。

2 个答案:

答案 0 :(得分:3)

您需要计算可观察的(http://knockoutjs.com/documentation/computedObservables.html

您的问题并非真实,所以我不知道您想要过滤的内容/方式。这是想法(psedo代码):

this.filteredArray = ko.computed(function(){
     var filtered = [];
     for (yourvar) // loop on your original array
       if (filter)
         filtered.push(yourvar[i])
    return filtered;
}, this);

在模型中添加此功能可以解决问题,然后您可以在filteredArray中使用var作为data-bind

<div data-bind="foreach: filteredArray">
   $data
</div>

答案 1 :(得分:1)

按照你提出的问题的方式,完全你要求的是什么,你可以订阅filterStoredProceduresInDB*By的更改事件并从那里覆盖数组,就像这样:

var filterCallback = function ( array, newValue ) {
    array( ko.utils.arrayFilter( array(), function ( storedProcedure ) {
        return storedProcedure.Profile === newValue;
    } ) );
};

self.filterStoredProceduresInDB1By.subscribe( filterCallback.bind( self, self.storedProceduresInDB1 ) );
self.filterStoredProceduresInDB2By.subscribe( filterCallback.bind( self, self.storedProceduresInDB2 ) );

这将直接覆盖您的可观察数组。但是,正如您可能会看到在this updated jsfiddle中测试一样,这不是一个好主意,因为您丢失了任何未通过过滤器的数据,因此以后无法更改过滤器很多手动管道来获取原始数据并在再次过滤之前将其重新放回到数组中。

这是计算可观察量的最佳和最常见的用例之一。创建一个计算的observable,它返回数组的过滤投影,而不是直接覆盖数组,正如人们在其他答案/评论中所指出的那样。

self.filteredStoredProceduresInDB1 = ko.computed( function () {
    var filterBy = self.filterStoredProceduresInDB1By();
    if ( !filterBy )
        return self.storedProceduresInDB1();
    return ko.utils.arrayFilter( self.storedProceduresInDB1(), function ( storedProcedure ) {
        return storedProcedure.Profile === filterBy;
    } );
} );

然后将显示的列表绑定到计算的observable。 Jsfiddle here