19
votes

I have been using Knockout.js for a lot of projects lately, and I am writing a lot of repetitive code. I would like to be able to define a BaseViewModel class and have my page-specific ViewModels inherit from it. I am a bit confused about how to do this is Javascript. Here is my basic BaseViewModel:

(function (ko, undefined) {
    ko.BaseViewModel = function () {
        var self = this;
        self.items = ko.observable([]);
        self.newItem = {};
        self.dirtyItems = ko.computed(function () {
            return self.items().filter(function (item) {
                return item.dirtyFlag.isDirty();
            });
        });
        self.isDirty = ko.computed(function () {
            return self.dirtyItems().length > 0;
        });
        self.load = function () { }
    };
}(ko));

I would like to be able to list signatures for methods like load in the BaseViewModel and then give them definitions in the inheriting ViewModel. Is any of this possible? I have found a few solutions online but they all rely on defining functions/classes to make the inheritance work.

2
why are you passing undefined into the function?Kyeotic
Huh, never seen that before. I've also never run into the case where not doing that causes a bug, and he doesn't explain what that case is.Kyeotic
It is a defensive technique if you are writing code to be consumed by others. It is possible to re-define the undefined symbol. Declaring a function parameter undefined and then not passing any value for that argument is a technique to capture the actual undefined value even if someone has redefined the symbol. As it happens, it also lets your JS minimizer minimize your usages of undefined since it is now just a local variable.Brandon

2 Answers

18
votes

Since your BaseViewModel is just adding all of the properties/methods to this (and not using prototype) then it is pretty easy:

In your new view models, just call BaseViewModel:

var MyVM = function () {
    var self = this;
    ko.BaseViewModel.call(self);

    self.somethingElse = ko.observable();
    self.itemCount = ko.computed(function() { return self.items().length; });
    self.items([1, 2, 3]); 
};


// ...
var vm = new MyVM();
10
votes

Javascript inheritance is done in two pieces. The first is in the constructor, and the second is on the prototype (which you aren't using, so you could skip).

var ViewModel = function(data) {
    BaseViewModel.call(this);
};
//you only need to do this if you are adding prototype properties
ViewModel.prototype = new BaseViewModel();

To your last point, about overriding load, its no different that putting a load function on your viewmodel normally. Javascript allows you to override any objects properties with anything, there are no special steps here.

Here is a fiddle demonstrating the inheritance.