2014-10-27 67 views
2

我一直在努力使我的JavaScript应用程序更具可扩展性。该应用程序使用knockout.js绑定某些类型的数据库项目的网格,以供用户编辑和更新。我现在正在继续使用继承,并拥有一个BaseModel和从中继承的模型。我遇到的问题出现在我想要覆盖由BaseModel中继承的类定义的计算观察值时。下面是用例。继承和重写敲除计算可观察

基本网格具有UI绑定的计算可观察值。计算出来的observable使用文本框过滤器处理可观察数组,并使用用户可以键入的文本框过滤器进行搜索。很基本。

子类,角色是特定类型的网格,部分业务需求是为部门设置过滤器。这是UI中的一个下拉菜单。我想用子类中的角色实现来覆盖基类中的计算可观察性。不知道如何做到这一点。

这里是一个的jsfiddle:http://jsfiddle.net/Icestorm0141/vx6843pt/6/

的BaseGridViewModel:

var BaseGridViewModel = function (serverData) { 
    var self = this;  

    //searchTerm is a text box that the user types to search 
    self.searchTerm = ko.observable(); 

    //items are the data from the server 
    self.items = ko.mapping.fromJS(serverData, mapping); 

    //filteredItems are the filtered list of items that the grid is actually bound to 
    //thus when the user searches, the UI updates automatically 
    self.filteredItems = ko.computed(function() { 
     if (self.searchTerm() == null || self.searchTerm() == "" || self.searchTerm().length < 3) { 
      return self.items(); 
     } 
     else { 
      return ko.utils.arrayFilter(self.items(), function (item) { 
       return item.Description().toLowerCase().indexOf(self.searchTerm().toLowerCase()) >= 0; 
      }); 
     } 
    }); 
} 

子类:

var RoleGridModel = function (roleData) { 
    var self = this; 

    //calling the base model, I think this is the proper way to do this? 
    BaseGridViewModel.call(self, roleData); 

    //UI has a drop down list of departments to filter by, this is the selected filter 
    self.departmentFilter = ko.observable(); 

    //I WANT to set the filter function for the items to something completely different 
    var filterOverride = function() { 
     if (self.departmentFilter() == null || self.departmentFilter() == "") { 
      return self.items(); 
     } 
     else { 
      return ko.utils.arrayFilter(self.items(), function (role) { 
       return role.DepartmentId() == self.departmentFilter(); 
      }); 
     } 
    }; 
} 

我已经做了很多的研究,这最近几天,我很惊讶我还没有遇到一个解决方案。我不觉得我做的事情太特别,但也许有人有一些建议。我向任何人开放!

回答

1

你需要重写filteredItems

self.filteredItems = ko.computed(filterOverride); 

Fiddle

+0

这应该很好。通过我的具体实现获得一些错误(我认为剑道网格试图在错误的时间绑定),但我认为一旦我解决了这个问题,这将工作得很好。谢谢! – Icestorm0141 2014-10-29 12:48:18

2

我假设你的意图是将基类过滤器与继承类的过滤器相结合,而不是简单地抛出基类过滤器。如果你只是想忽略基类过滤器,你可以简单地覆盖self.filteredItems,就像haim770的答案一样。

否则,有很多方法可以解决这个问题。一种方法是做这样的事情:

//In RoleGridModel 
var baseFilteredItems = self.filteredItems; //Keep a reference to the base class's implementation 
self.filteredItems = ko.computed(function() { 
    var baseItems = baseFilteredItems(); 
    return filterByDepartment(baseItems); //filtering logic goes here 
}); 

这基本上你想要做什么,是最接近模拟“重写”一个计算。


除了“覆盖”计算的方法之外,另一种方法是修改基类以支持任意过滤器。喜欢的东西:

//BaseGridViewModel: 

var filters = ko.observableArray([]); 
self.addFilter = function(filterFunction) { 
    filters.push(filterFunction); 
} 

self.filteredItems = ko.computed(function() { 
    var items = self.items(); 
    filters().forEach(function (filter) { 
     //filters could also be implemented to take individual items and return true or false whether that item should be filtered, but that's a side point 
     items = filter(items); 
    }); 
    return items; 
}); 

var searchFilter = function (items) { 
    var filteredItems = // filtering logic here 
    return filteredItems; 
}; 

self.addFilter(searchFilter); 

//RoleGridModel 
var departmentFilter = function (items) { 
    var filteredItems = // filtering logic here 
    return filteredItems; 
} 

self.addFilter(departmentFilter) 

这是在继承类一点更可读的,虽然它需要在基类更多的逻辑。

+0

这是非常有帮助的,我甚至没有想过将基类过滤器与覆盖组合在一起。 我想我需要的是haim770发布的内容。似乎还有其他事情正在进行,但导致用户界面崩溃。可能是绑定到剑道网格,阻止它的工作。但至少现在我知道如何去做我正在寻找的基本原则。谢谢! – Icestorm0141 2014-10-29 12:46:32

+0

非常有帮助的回答!希望我可以多次赞扬它! – 2016-10-06 07:02:29

0

对于任何可能发现Retsam解决方案的人都很有帮助 - 我后来需要使用它,在声明addFilter时出现语法错误。校正的sytnax是:

self.addFilter = function(filterFunction) { 
    filters().push(filterFunction); 
} 

此外,因为过滤器是一个observableArray其中的项目没有被跟踪。因此,我传入的每个过滤函数都是最初计算的观测值,因为它们具有它们依赖的可观测值。例如:

self.addFilter(function() { 
//used to be wrapped in a computed observable 
    if (self.searchTerm() == null || self.searchTerm() == "" || self.searchTerm().length < 3) { 
     return self.items(); 
    } 
    else { 
     return ko.utils.arrayFilter(self.items(), function (item) { 
      return item.Description().toLowerCase().indexOf(self.searchTerm().toLowerCase()) >= 0; 
     }); 
    } 
}); 

在这个例子中,第一滤波器函数取决于SEARCHTERM(),但因为其被添加到过滤器阵列,这仅仅是可观察到的阵列,所述UI没有更新时SEARCHTERM已更新。我不得不手动触发通过订阅的更新是需要更新UI时,过滤后可观察到的每个:

self.searchTerm.subscribe(function (newValue) { 
    filters.valueHasMutated(); 
}); 

有可能是一个更好的方式来做到这一点,但我还没有找到一个。