0

I want to setup nested namespaces to organize my code. I am trying to follow the plugin-like structure described in this article. The problem is I don't understand how to access this.error_msg in my example. Have I set this up correctly? Would I have to use jQuery .extend or .prototype to access this.error_msg?

(function(TC, $, undefined){

    TC.ajax = function() {
        this.error_msg = 'default error...';         
    };

    TC.ajax.run = function(){
        //do stuff...
        TC.ajax.handle_error();
    };

    TC.ajax.handle_error = function(){
        alert(this.error_msg);
    };        

}(window.TC = window.TC || {}, jQuery));

// Test it
TC.ajax.run();

Demo: http://jsfiddle.net/g99yt/

Justin
  • 26,443
  • 16
  • 111
  • 128

5 Answers5

3

The important thing to remember is that each time you use function(), you are creating a new scope. So you can see that in your TC.ajax.handle_error method that this.error_msg is undefined because you haven't defined it in that scope. One thing you can do is prototype to make sure those methods relate back to your ajax object and declare a new instance of the object, and then call your methods on that. see below :

(function(TC, $, undefined){

    TC.ajax = function() {
        this.error_msg = 'default error...';         
    };

    TC.ajax.prototype.run = function(){
        //do stuff...
        this.handle_error.call(this);
    };

    TC.ajax.prototype.handle_error = function(){
        alert(this.error_msg);
    };        

}(window.TC = window.TC || {}, jQuery));

// Test it
 var ajaxInstance = new TC.ajax();

ajaxInstance.run();

and the fiddle

you do have other options like keeping a locally global variable like @kta does, or by setting your scope through the call function, but that doesn't really apply well to your structure.

Evan
  • 5,975
  • 8
  • 34
  • 63
  • This maintains scope well unlike the other solutions. It sucks to add the step of having to create an instance, but I understand why that is required. – Justin Mar 14 '13 at 22:51
  • glad I could help. it's probably a good idea to get into the practice of creating instances if you plan on getting into more indepth object oriented javascript – Evan Mar 14 '13 at 23:00
2

I think your code must look something like this:

(function(TC, $, undefined){
    _this = this;
    TC.ajax = function() {
        _this.error_msg = 'default error...';         
    };

    TC.ajax.run = function(){
        //do stuff...
        TC.ajax.handle_error();
    };

    TC.ajax.handle_error = function(){
        alert(_this.error_msg);
    };        

}(window.TC = window.TC || {}, jQuery));

// Test it
TC.ajax.run();
catacs
  • 191
  • 7
  • This works but I am trying to avoid `error_msg` being global (under TC) in scope. I want it only accessible from TC.ajax and functions nested below that. So when I wrote `this.error_msg` what I meant was `TC.ajax.error_msg`. So far it looks like I'd need to use prototype for this, as described by Evan... Unless you know another way? – Justin Mar 14 '13 at 21:06
0

It's actually a common problem, it's not immediately clear what this refers to. So to explain:

TC.ajax.handle_error = function(){
    alert(this.error_msg);
};   

The this in the TC.ajax.handle_error function refers to the function and not your TC object. So just save the reference to TC so you can refer to it later:

var _this = this;

...
_this.error_msg = 'default error....';
...

TC.ajax.handle_error = function(){
     alert(_this.error_msg);
 };        
Amy
  • 7,388
  • 2
  • 20
  • 31
  • Hmmm, but I am trying to reference TC.ajax.error_msg, not TC.error_msg. How would this apply to that scope? – Justin Mar 14 '13 at 21:01
  • @Justin Sorry I'll clarify the answer, `TC` has `error_message` as a property, so having that reference to `TC` allows you to access `TC.error_msg`. – Amy Mar 14 '13 at 21:22
0

If TC.ajax is supposed to be a constructor, then run() and handle_error() need to be added to a prototype.

But you could do something like

TC.ajax = {};    
TC.ajax.error_msg = 'default error...'; 

In your case error_msg will be assigned to this as soon as you call TC.ajax(), which never happens. And even then, this would refer to TC. And when TC.ajax.handle_error()is called, this refers to TC.ajax.

a better oliver
  • 26,330
  • 2
  • 58
  • 66
0

This is what I ended up using:

(function ($, TC, undefined) {

    TC.nestedNamespace = TC.nestedNamespace || {};

    //add a public function to our new namespace 
    TC.nestedNamespace.test = function () {        
       console.log("Winning!");    
    };

}(jQuery, window.TC = window.TC || {}));

TC.nestedNamespace.test();

Example JSFiddle. I found this method in the comments of a related article.

Justin
  • 26,443
  • 16
  • 111
  • 128