Knockout JS查看刷新和过滤

时间:2014-10-15 14:49:40

标签: asp.net-mvc-4 knockout.js

我是Knockout的新手,所以请耐心等待。我有一个数据表,我试图从表格标题部分的文本框中动态过滤。我只能在文本框中添加一个字符,然后过滤数据并且控件失去焦点。例如,我无法输入" XX"因为过滤动作是在第一个" X"输入并从文本框中删除光标。

这是我的灵感 - http://jsfiddle.net/Xpx7f/20/

这是标记

   // This where I'm filtering
   <thead>               
       <tr data-bind="foreach: columnNames">
           <td>
               // why isn't this "data-bind="textInput: filters"?
               // the observable name is filters not filter
               <input type='text' data-bind="textInput: filter" /> 
           </td>
       </tr>
   </thead>

   <tbody data-bind="foreach: enrollments">
       <tr>
          <td data-bind="text: WinId"></td>
          <td data-bind="text: EffectiveYear"></td>
          <td data-bind="text: FileKeeperGroupId"></td>                    
       </tr>
    </tbody>  

这里是淘汰赛

   var viewModel = (function(){
            self = this;
            self.enrollments = ko.observableArray([]);  
            self.filters = ko.observableArray([]); 

            self.filteredItems = ko.computed(function () {                  
                var filter = self.filters(); 
                var enrollments = ko.utils.arrayFilter(self.enrollments(), function (item) {
                    for (var col in filter) {                    
                        var v = (item[col] || '').toString(); // column value
                        var f = filter[col]; // what's typed in header
                        if (v.lastIndexOf(f, 0) === 0) return true;
                    }
                    return false;
                });

                if(enrollments.length > 0)
                {
                    self.enrollments(enrollments);
                }
                else{
                    return self.enrollments();
                }
            });

            var subscriptions = [];
            self.columnNames = ko.computed(function () {
                ko.utils.arrayForEach(subscriptions, function (s) { s.dispose(); });
                subscriptions = [];
                if (self.enrollments().length === 0) return [];
                var props = [];
                var obj = self.enrollments()[0];
                for (var name in obj) {         
                    var p = { name: name, filter: ko.observable('') };
                    subscriptions.push(p.filter.subscribe(filterOnChanged, p));
                    props.push(p);
                }                      
                return props;
            });

            var filterOnChanged = function (value) {
                var filters = self.filters();
                filters[this.name] = value;            
                self.filters(filters);     
            };                
        });

        $(document).ready(function(){
            var vm = new viewModel();
            vm.getRecords();
            ko.applyBindings(viewModel);
        });

1 个答案:

答案 0 :(得分:0)

看起来这种情况正在发生,因为您的 self.columnNames 是一个计算的可观察对象,它取决于 self.enrollments observable。应用过滤器时, self.enrollments observable会发生变化。当你的 self.columnNames observable得到更新时,重新绑定就会发生,一切都会被重新渲染,你就会失去焦点,因为DOM元素是新的。

我会移动逻辑以在单独的函数中构建列:

function initColumns () {
    ko.utils.arrayForEach(subscriptions, function (s) { s.dispose(); });
    subscriptions = [];
    if (self.enrollments().length === 0) return [];
    var props = [];
    var obj = self.enrollments()[0];
    for (var name in obj) {         
         var p = { name: name, filter: ko.observable('') };
         subscriptions.push(p.filter.subscribe(filterOnChanged, p));
         props.push(p);
     }                      
    return props;
});

然后在初始化columnNames可观察数组时调用此函数。

self.columnNames = ko.observableArray(initColumns());

否则你会陷入这种自我更新的循环地狱。

基于小提琴更新

好的,你要做的就是删除self.filteredItems并创建一个如下所示的计算observable:

self.filteredEnrollments = ko.computed(function () {                  
    var filter = self.filters(); 
    return ko.utils.arrayFilter(self.enrollments(), function (item) {
        for (var col in filter) {                    
            var v = (item[col] || '').toString(); // column value
            var f = filter[col]; // what's typed in header
            if (v.lastIndexOf(f, 0) === 0) return true;
        }
        return false;
    });
});

在你的html中,绑定到filteredEnrollments而不是注册。

<tbody data-bind="foreach: filteredEnrollments">
    <tr>
        <td data-bind="text: WinId"></td>
        <td data-bind="text: EffectiveYear"></td>
       <td data-bind="text: FileKeeperGroupId"></td>                    
    </tr>
</tbody>  

这样您就不会更改注册可观察数组,该数组不会触发计算重新绑定DOM的 columnNames