我一直致力于让我的javascript应用程序更具可扩展性。该应用程序使用knockout.js绑定某个类型的数据库项目的网格,以供用户编辑和更新。我现在正在继续使用继承并拥有BaseModel和继承的模型。当我想要覆盖由继承自它的类在BaseModel中定义的计算的observable时,我遇到的问题就出现了。这是用例。
基础网格具有UI绑定的计算可观察对象。计算出的observable使用文本框过滤器对可观察数组进行操作,用户可以键入该文本框过滤器进行搜索。非常基本。
子类,角色,是特定类型的网格,业务要求的一部分是为部门设置过滤器。这是用户界面中的下拉菜单。我想用子类中的角色实现覆盖基类中的计算观察者。不知道如何做到这一点。
这是一个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();
});
}
};
}
过去几天我一直在做很多研究,我很惊讶我还没有找到解决方案。我不觉得我做了太多非凡的事情,但也许有人有一些建议。我对任何人开放!
答案 0 :(得分:2)
我假设您的意图是将基类过滤器与继承类的过滤器结合起来,而不是简单地抛弃基类过滤器。如果您只想忽略基类过滤器,则可以像haim770的答案一样覆盖self.filteredItems
。
否则,有很多方法可以解决这个问题。一种方法是做这样的事情:
//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
});
这基本上是你想要的,并且最接近&#34;覆盖&#34;计算。
另一种方法,除了&#34;覆盖&#34;计算,将修改基类以支持任意过滤器。类似的东西:
//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)
这在继承类中更具可读性,但它在基类中需要更多逻辑。
答案 1 :(得分:1)
答案 2 :(得分: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(),但由于它被添加到filters数组(这只是一个可观察的数组),因此在更新searchTerm时UI不会更新。我必须通过订阅手动触发更新,以便在过滤时更新UI所需的每个observable:
self.searchTerm.subscribe(function (newValue) {
filters.valueHasMutated();
});
可能有更好的方法可以做到这一点,但我还没有找到。
答案 3 :(得分:-1)