Search code examples
backbone.jsknockout.jsoverridingextend

Overriding Knockout View-Model function


I am using knockout and backbone in my application. My test-view.js look like this:

define([
  "knockout",
  "./base",
  "./../viewmodels/test-vm",
  "text!./../templates/test-template.html"
],

function(ko, BaseView, TestViewModel, template) {

  var TestView = BaseView.extend({
    template: template,

    initialize: function() {
      this.viewModel = new TestViewModel();
    },

    render: function(){
      this.$el.html(template);
      return this;
    },

    postRender: function() {
      ko.applyBindings(this.viewModel, this.el);
    }
  });

  return TestView;
});

test-template.html:

<button class="btn"  data-bind="click: test">test</button>

and test-vm.js as follows:

define([],
  function() {

    function TestViewModel() {
      var self = this;

      self.test = function () {
        alert("in test view model");
      };
    }

    return TestViewModel;
  });

When I click button, self.test is invoked. My question is how can I extend TestViewModel in another file and override test function to do some specific things? Thanks in advance!


Solution

  • I don't see any reason you can't use the commonly used "Classical inheritance with Object.create" approach as described here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create

    // Define the base class
    var TestViewModel = function () {
      this.sharedProperty = true;
    };
    
    TestViewModel.prototype.test = function() {
      log("testing TestViewModel");
    };
    
    // Define the extended class
    var ExtendedTestViewModel = function() {
      TestViewModel.call(this);
    };
    
    // Copy the prototype and reset the constructor
    ExtendedTestViewModel.prototype = Object.create(TestViewModel.prototype);
    ExtendedTestViewModel.constructor = ExtendedTestViewModel;
    
    // Override the inherited `test` function
    ExtendedTestViewModel.prototype.test = function() {
      // To call the base method: 
      // (skip this if you want to completely override this function)
      TestViewModel.prototype.test.call(this);
      
      // Add functionality:
      log("testing ExtendedTestViewModel");
    };
    
    // Create an instance
    var etvm = new ExtendedTestViewModel();
    
    // This will log both the inherited message, as well as the extended message
    etvm.test();
    
    // ExtendedTestViewModel has all properties that are in TestViewModel
    log(etvm.sharedProperty);
    
    // utils
    function log(msg) {
      var pre = document.createElement("pre");
      pre.appendChild(document.createTextNode(msg));
      document.body.appendChild(pre);
    };