2

我一直在努力使我的 javascript 应用程序更具可扩展性。该应用程序使用 knockout.js 绑定某种类型的数据库项目的网格,以供用户编辑和更新。我现在正在使用继承并拥有一个 BaseModel 和从中继承的模型。当我想覆盖一个由继承自它的类在 BaseModel 中定义的计算 observable 时,我遇到的问题就出现了。这是用例。

基础网格有一个 UI 绑定到的计算 observable。计算出的 observable 使用带有文本框过滤器的 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();
            });
        }
    };
}

过去几天我一直在对此进行大量研究,但我很惊讶我还没有找到解决方案。我不觉得我做的事情太特别了,但也许有人有一些建议。我对任何人都开放!

4

4 回答 4

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)

这在继承类中更具可读性,尽管它需要基类中的更多逻辑。

于 2014-10-28T21:46:25.473 回答
1

您需要覆盖filteredItems

self.filteredItems = ko.computed(filterOverride);

小提琴

于 2014-10-27T22:22:40.400 回答
0

对于其他可能发现 Retsam 的解决方案有用的人——我需要使用它,声明 addFilter 时出现语法错误。更正后的语法是:

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

此外,由于过滤器是一个 observableArray,因此其中的项目没有被跟踪。所以我传入的每个过滤器函数最初都是计算出的 observables,因为它们有它们所依赖的 observables。例子:

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(),但是由于它被添加到过滤器数组中,它只是一个可观察的数组,所以当 searchTerm 更新时 UI 没有更新。我必须通过订阅手动触发更新,以便在过滤时需要更新 UI:

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

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

于 2014-11-18T18:50:15.837 回答
-1

我会使用继承库来实现快速可靠的继承就像,

https://github.com/dotnetwise/Javascript-FastClass

例如你的方法不支持原型

于 2014-10-28T10:16:19.853 回答