25
votes

I have three relatively similar knockout models in my application and I would like to extend a base model to combine common properties rather than repeat myself three times.

example

var ItemModel = function (item) {
  var self = this;

  self.order = ko.observable(item.order);
  self.title = ko.observable(item.title);
  self.price = ko.observable(item.price);
  self.type = ko.observable(item.type);
};

var StandardItemModel = function (item, cartItemTypes) {
  var self = this;

  self.order = ko.observable(item.order);
  self.title = ko.observable(item.title);
  self.price = ko.observable(item.price);
  self.type = ko.observable(item.type);

  self.isInCart = ko.computed(function () {
    return cartItemTypes().indexOf(item.type) > -1;
  }, self);

  self.itemClass = ko.computed(function () {
     return self.isInCart() ? "icon-check" : "icon-check-empty";
  }, self);
};

var CustomItemModel = function (item) {
  var self = this;

  self.order = ko.observable(item.order);
  self.title = ko.observable(item.title);
  self.price = ko.observable(item.price);
  self.type = ko.observable(item.type);

  self.icon = item.icon;
};

I would like to use ItemModel as a base class and just add the extra properties as necessary.

5
OK, but what is your question? What problems do you have during the base class creation?nemesv
my question is what is the best approach to doing this in javascript and if knockout provides some utility to simplify it.BillPull

5 Answers

41
votes

I think you can use ko.utils.extend like this

ko.utils.extend(self, new ItemModel(item));

inside the StandardItemModel

like this: http://jsfiddle.net/marceloandrader/bhEQ6/

0
votes

I guess you can do something like this:

var StandardItemModel = function (item, cartItemTypes) {
var self = this;
self.standard = new ItemModel(item);
self.isInCart = ko.computed(function () {
return cartItemTypes().indexOf(item.type) > -1;
}, self);

self.itemClass = ko.computed(function () {
 return self.isInCart() ? "icon-check" : "icon-check-empty";
 }, self);
}
0
votes

You can chain constructor calls using .call or .apply

function ItemModel (item) {
    var self = this;

    self.order = ko.observable(item.order);
    self.title = ko.observable(item.title);
    self.price = ko.observable(item.price);
    self.type = ko.observable(item.type);
}

function StandardItemModel(item, cartItemTypes) {
    var self = this;

    ItemModel.call(this, item);

    self.isInCart = ko.computed(function () {
        return cartItemTypes().indexOf(item.type) > -1;
    }, self);

    self.itemClass = ko.computed(function () {
        return self.isInCart() ? "icon-check" : "icon-check-empty";
    }, self);
}

function CustomItemModel (item) {
    var self = this;

    ItemModel.apply(this, [item]);

    self.icon = item.icon;
}

The advantage over ko.utils.extend (or similar methods from jQuery, underscore, etc) is that you are not creating an additional object just to grab references to its methods.

0
votes
function MyBaseType() {
    var self = this;
    self.Id = 1
}

function MyComplexType() {
    var self = this;

    //Extending this class from MyBaseType
    ko.utils.extend(self, new MyBaseType());

    self.Name = 'Faisal';

    self.MyComplexSubType = new MyComplexSubType();
}

function MyComplexSubType() {
    var self = this;

    self.Age = 26;
}

JSFIDDLE EXAMPLE

-1
votes

I've done something similar, with a lot of trial and error, but I got this to work for me:

var StandardItemModel = function (item, cartItemTypes) {
    var self = this;
    ItemModel.call(self, item)
}

You then need to add a prototyped constructor:

StandardModel.prototype = new ItemModel();

If you want to have common methods, then you need to add them to the base classes using prototype to add them, then call them in the higher class using:

ItemModel.prototype.methodName.call(self, parameters);