继承和重写Knockout计算可观察
Inheritance and overriding Knockout computed observable
我一直在努力提高javascript应用程序的可扩展性。该应用程序使用knockout.js绑定某种类型的数据库项的网格,由用户编辑和更新。我现在正沿着继承的道路前进,并拥有一个BaseModel和从中继承的模型。当我想覆盖一个计算的可观测值时,我遇到的问题就来了,这个可观测值是由它继承的类在BaseModel中定义的。
基本网格有一个计算的可观察对象,UI绑定到该可观察对象。计算的可观测对象通过一个文本框过滤器来处理可观察数组,用户可以键入该过滤器进行搜索。相当基础。
子类角色是一种特定类型的网格,业务需求的一部分是为部门提供过滤器。这是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();
});
}
};
}
在过去的几天里,我对此做了很多研究,我很惊讶还没有找到解决方案。我不觉得我在做什么特别的事情,但也许有人有一些建议。我对任何人都持开放态度!
我假设您的意图是将基类过滤器与继承类的过滤器结合起来,而不是简单地抛出基类过滤器。如果您只是想忽略基类过滤器,您可以简单地覆盖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)
这在继承类中可读性稍高,尽管它在基类中需要更多的逻辑。
您需要覆盖filteredItems
:
self.filteredItems = ko.computed(filterOverride);
请参阅Fiddle
对于其他可能觉得Retsam的解决方案很有用的人——我后来需要使用它——在声明addFilter时出现了语法错误。校正后的sytnax为:
self.addFilter = function(filterFunction) {
filters().push(filterFunction);
}
此外,因为filter是一个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;
});
}
});
在本例中,第一个filter函数依赖于searchTerm(),但由于它被添加到filter数组中,而filter数组只是一个可观察的数组,因此在更新searchTerm时UI没有更新。我必须通过订阅手动触发每个可观察到的更新,当过滤时需要更新UI:
self.searchTerm.subscribe(function (newValue) {
filters.valueHasMutated();
});
也许有更好的方法可以做到这一点,但我还没有找到。
我会使用继承库来实现快速可靠的继承比如
https://github.com/dotnetwise/Javascript-FastClass
例如,您的方法不支持原型
- 下拉列表未从计算的可观察项更新
- 在编辑记录上可观察的挖空 JS 计算
- 挖空映射:加载数据后,父模型中的计算可观察量不会更新
- Knockout.js:在可选定义的值上计算可观察性
- 如何使用ES6在Ember中声明可观察性或计算属性
- 击倒计算的可观察到的未发射'写'
- 向KO传递在对象内可观察到的计算值
- 如何使某些可观察的“独立”计算可观察(Knockout.js)
- 如何在运行时向计算可观察量添加其他数组项
- Knockout.js - 如何在计算的可观察量中获取可观察属性的值
- 在不重置对象的情况下重新计算计算可观察量
- 从计算的可观察量中获取价值
- Knockout的可写计算在AngularJS中可观察的模拟是什么?
- 使挖空计算订阅不在初始执行路径中的可观察量
- 如何在淘汰.js中实现可计算的可观察量
- 根据异步数据计算的可观察量
- .replace() 表达式未在计算可观察量中更新
- 对计算可观察量的挖空 JS 绑定不起作用
- 挖空添加计算中断可观察数组
- 将通过原型计算的可观察对象添加到构造函数中