继承和重写Knockout计算可观察

时间:2014-10-27 21:35:51

标签: javascript inheritance knockout.js computed-observable

我一直致力于让我的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();
            });
        }
    };
}

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

4 个答案:

答案 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)

您需要覆盖filteredItems

self.filteredItems = ko.computed(filterOverride);

请参阅Fiddle

答案 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)

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

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

例如,您的方法不支持原型