views:

61

answers:

3
var Test = (function() {
    return {
        useSub: function () {
            this.Sub.sayHi();
        },

        init: function () {
            $(document).ready(this.useSub);
        }
    };
})();

Test.Sub = (function () {
    return {
        sayHi: function () {
            alert('hi');
        }
    };
})();

Test.useSub(); // works
Test.init(); // explodes

Above I am trying to create a Test namespace and add an object Sub to it. I was doing fine until I tried using the object in jQuery. The error is "Uncaught TypeError: Cannot call method 'sayHi' of undefined". If there is a better way to do this, I am open to it.

Edit:

Obviously this was demo code. In my real application the solution that I went with because I think it is the most clear is this one:

var Namespace (function () {
  return {
    init: function () {
      $(document).ready(function() {
        Namespace.onReady();
      }
    },
    onReady: function() {
      alert('Now I am back in the Namespace scope. Proceed as planned');
    }
  };
})();

Edit2: All jQuery callbacks seem to require they are used in this manner or else the scoping is screwed up.

+2  A: 

Here is one way

var Test = {
  useSub : function () { 
    Test.Sub.sayHi(); 
  }, 
  init: function () { 
    $(document).ready(Test.useSub); 
  },
  Sub: {
    sayHi: function () { 
      alert('hi'); 
    } 
  }
};
John Hartsock
This doesn't work. It has the same problem.
Fletcher Moore
@fletcher Moore....yeah sorry about that I forgot to replace this with Test
John Hartsock
+5  A: 

I think it is a scope problem. If you do

$(document).ready(this.useSub);

then this.useSub will be executed in the window scope (so inside the function, this refers to the window object) and there doesn't exist a Sub attribute.

Try:

init: function () {
    var obj = this;
    $(function(){obj.useSub()});
}

For some reason it does not work using $(document).ready(function(){obj.useSub()}); but it works with the $() shortcut.

Felix Kling
+1 I prefer `that = this` but yes, this is the solution.
Skilldrick
var that = this;$(document).ready(function () {that.useSub();});Works for me.
Skilldrick
@Skilldrick: I tested it with JS Bin and it does not work there, but then it has probably to do with their setup.
Felix Kling
Using it in ready() also works for me. Thanks for your help.
Fletcher Moore
@Felix I'm in jsFiddle and it works there :) : http://jsfiddle.net/qJmAk/
Skilldrick
+1  A: 

in this line:

$(document).ready(this.useSub);

you're passing a reference to a function and the scope is lost- when the function runs, this no longer means Test.

lincolnk