0

I am new to javascript and my question might be outrightly stupid. I am not able to get the correct reference for this.

I am trying to write a controller object in javascript. The idea here is to make this an interface object where anyone can inherit from its prototype and override the methods for their being.

I just want to expose one method "process()" to the object and this method will call all the remaining methods and attributes. I am trying to achieve this by making all the other methods and attributes private by using closures. this is the sample snippet of my code

var ViewController = function() {

    var _viewName = null;


  var loadView = function(viewName) {

    console.log("now loading view : "+viewName+ " ...");
  };

    return {
        process : function(viewName){
            _viewName = viewName;
            loadView(_viewName);
        }
    };

};


var vController = ViewController();
vController.process("alphaView");

Now this works perfectly fine. But if I want to override the methods PreProcess, loadView, initView and PostProcess using prototype, it doesn work. I tried overriding using the Object.create like

var vController2 = Object.create(ViewController, {

  LoadView : function(viewName) {
    //some custom implementation
  },
  //and so forth
});

And if I change my implementation to define the methods outside using prototypes also doesn't work. Like

 var ViewController = function() {

      var _viewName = null;

      return {
        process : function(viewName){
          _viewName = viewName;
          loadView(_viewName);
        }
      };

    };

    ViewController.prototype.loadView = function(viewName) {

        console.log("now loading view : "+viewName+ " ...");
    };

The gist of my issue being that I want (a) an interface object for a controller where the user can override the the one basic method (LoadView,) (b) All these members are private to the controller object and be accessible via the "Process()" method

Please advise!

EDIT: edited the code to make it simple.

curioussam
  • 439
  • 3
  • 9
  • 19
  • Please reduce your code to a minimal (or at least shorter) example of what you're trying to do. – Dave Mar 17 '13 at 22:28
  • If you want to override methods from outside the implementation, then don't make them private, local functions. Instead, add them to the actual object prototype. It's unclear what problem you're really trying to solve by only having one actual method `process()`. That sounds like your skirting the normal javascript features. – jfriend00 Mar 17 '13 at 22:30
  • what I want is that a developer can actually create an inherited object of ViewController and implement its own LoadView method. For eg. the application can have multiple controllers, say controller1, controller2 etc and each doesn a different operation on its LoadView. But the controller object , whenever or wherever instantiated can call only process() i.e. the only way of calling LoadView is via process(). I might have got it all wrong and thats why i needed the advise. – curioussam Mar 17 '13 at 22:36
  • I think the main source of confusion here (after what jfriend00 has said) is that f you return an _Object_ from a constructor invoked with `new`, it throws away the constructor's own instance in favour of the returned object, which doesn't (necessarily/by default) inherit the same _prototype_ as the constructor would. You may find [**this answer**](http://stackoverflow.com/a/13214563/1615483) helpful. – Paul S. Mar 17 '13 at 22:40
  • @curioussam - OK, now that I better understand what you're trying to do, I added another option to my answer. – jfriend00 Mar 17 '13 at 22:46

1 Answers1

1

Put the methods you want people to be able to override on the prototype so they are real methods and are called as real methods by process(). Then, once you create an object of this type, you can create new override defintions for any methods and process() will automatically call them instead of the originals. One way to do that is like this:

function ViewController() {
}

ViewController.prototype = {
    loadView: function(viewName) {
        console.log("now loading view : "+viewName+ " ...");
    },
    preProcess: function(viewName) {
        console.log("now Pre Processing view : "+viewName+ " ...");
    },
    // other methods here ...
    process: function(viewNmae) {
        this.viewName = viewName;
        console.log(_viewName);
        this.preProcess(_viewName);
        this.loadView(_viewName);
        this.initView(_viewName);
        this.postProcess(_viewName);
    }
}

var controller = new ViewController();
controller.loadView = function(viewName) {
    // override function for loadView
}
controller.process(viewName);

If, you really want to prohibit the calling of the override methods, then you would have give up using javascript's built-in prototype mechanism (because it's public and any method there can be called). So, you could use your own scheme and just add new public methods for setting the override functions. In your existing code, change this:

return {
    process : function(viewName){
        _viewName = viewName;
        loadView(_viewName);
    }
};

to this:

return {
    process : function(viewName){
        _viewName = viewName;
        loadView(_viewName);
    },
    setLoadViewFn: function(fn) {
        loadView = fn;
    }
    // add other override setting functions here
};


// create controller object
var controller = new ViewController();
// set override function for loadView
controller.setLoadViewFn(function(viewName) {
    // override function for loadView
});
controller.process(viewName);
jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • so looks like using closure here to make these members "private" is not a good option. This is a paradigme shift for me as I came from a classic OO language – curioussam Mar 17 '13 at 22:38
  • It's not a good option if you want to use javascript's built-in object/prototype features. You could use your scheme, but you'd have to make public methods for setting the override functions and store those in your own private instance data. That's the only way I know of to allow setting of the methods, but no way to call them outside of `process()`. – jfriend00 Mar 17 '13 at 22:40
  • @curioussam - Now that you've better described what you're trying to do, I've added another option using your existing code privacy mechanisms. – jfriend00 Mar 17 '13 at 22:43
  • this makes sense and I can see some abstraction and encapsulation here! This might work. Thanks :) – curioussam Mar 17 '13 at 22:47
  • this approach doesnt seem to work as it gives back an error, "SyntaxError: Expected an identifier but found 'function' instead " – curioussam Mar 18 '13 at 00:54
  • @curioussam - the approach will work, but I need to see your actual code you are using to help you figure out what isn't right. – jfriend00 Mar 18 '13 at 02:44
  • I am using the exact code as above. But when I run it, my original _preProcess, _loadView, _initView and _postProcess are called ...in the above example, the original _loadView is called and not the new overrided one – curioussam Mar 18 '13 at 04:42
  • you are right. My apologies! In the return function, I was using 'this' instead of 'that' or not using anything, Thanks a lot! – curioussam Mar 18 '13 at 19:03