Asp.net mvc 4 淘汰JS视图刷新和过滤

Asp.net mvc 4 淘汰JS视图刷新和过滤,asp.net-mvc-4,knockout.js,Asp.net Mvc 4,Knockout.js,我是个新手,所以请耐心点。我有一个数据表,我正试图从表的标题部分的文本框中动态筛选它。我只能在文本框中添加一个字符,然后数据被过滤,控件失去焦点。例如,我无法键入XX,因为当输入第一个X并且从文本框中删除光标时,过滤操作将启动并完成 这是我的灵感- 这是标记 // This where I'm filtering <thead> <tr data-bind="foreach: columnNames">

我是个新手,所以请耐心点。我有一个数据表,我正试图从表的标题部分的文本框中动态筛选它。我只能在文本框中添加一个字符,然后数据被过滤,控件失去焦点。例如,我无法键入XX,因为当输入第一个X并且从文本框中删除光标时,过滤操作将启动并完成

这是我的灵感-

这是标记

   // 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>  

看起来发生这种情况是因为您的self.columnNames是一个计算的可观察对象,它依赖于self.enrollments可观察对象。当应用筛选器时,self.enrollments observable会发生更改。当您的self.columnnamesobservable更新时,会发生重新绑定,所有内容都会重新呈现,您会因为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());
否则你会陷入这个自我更新的循环地狱

基于fiddle的更新

好的,那么您要做的是删除self.filteredItems,并创建一个计算的可观察对象,如下所示:

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中,绑定到FiltereDenRolls而不是注册

<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。

self.columnNames->是否有任何理由对其进行编译?它可以防止字段名被硬编码,但我可能100%错误。好吧,我看不到您的self.rollments在哪里填充。据我所知,你是根据注册中的第一个元素来构建专栏名的。按照我在回答中提出的方法来尝试,看看会发生什么。我认为你的逻辑是正确的,但我无法让它发挥作用。文本框不在那里,我的表也没有记录。还有,为什么我把-self.columnNames=ko.observearrayinitcolumns;?放在哪里很重要;???如果我把它放在虚拟机的顶部,我会得到一个数组错误。self.filteredItems中的filter变量是空的,所以它返回false。你能创建JSFIDLE吗?我应该可以,但我需要等到明天,因为它在代码中不是直接的。我很难提取正确的代码和数据放在小提琴中。然而,这把小提琴正是我想要做的-
<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>