javascriptinheritanceknockout.jscomputed-observable

Inheritance and overriding Knockout computed observable


I've been working on making my javascript app more scaleable. The app uses knockout.js to bind a grid of some type of database item to be editted and updated by the user. I'm now going down the path of working with inheritance and having a BaseModel and models that inherit from that. The problem I'm having comes in when I want to override a computed observable that is defined in the BaseModel by the class the inherits from it. Heres the use case.

Base grid has a computed observable that the UI binds to. The computed observable works off an observable array with a text box filter that the user can type to search with. Pretty basic.

The child class, roles, is a specific type of grid and part of the business requirement was to have a filter for the department. This is a drop down in the UI. I want to override the computed observerable in the base class with the roles implementation in the child class. Not sure how to accomplish that.

Here is a JSFiddle: http://jsfiddle.net/Icestorm0141/vx6843pt/6/

The 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;
            });
        }
    });
}

The Child Class:

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();
            });
        }
    };
}

I've been doing a lot of research into this the last few days and I'm surprised I haven't come across a solution yet. I dont feel like I'm doing anything too extraordinary but maybe someone has some suggestions. I'm open to any!


Solution

  • You need to override filteredItems:

    self.filteredItems = ko.computed(filterOverride);
    

    See Fiddle