Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to span javascript namespace across multiple files?

I have ignored javascript forever. I started using jQuery a few years back so I could get by. But as I've started doing TDD more I decided yesterday to really dive into javascript (and possibly coffeescript after that).

In my ASP.NET Web Forms application I have many pages and currently most of those pages do not have a ton of javascript. I'm in the process of changing that. I'm using Jasmine with Chutzpah to create my tests.

I was moving along with my tests passing and failing as expected. But then I wanted to create a namespace so I wouldn't be trampling all over global space.

After reading this article: http://enterprisejquery.com/2010/10/how-good-c-habits-can-encourage-bad-javascript-habits-part-1/

I decided to try and use the pattern from the Self-Executing Anonymous Function: Part 2 (Public & Private) section of the article. It appears to have the most flexibility and appears to encapsulate things very well.

I have a folder called /Scripts. Under that folder are some of the frameworks I'm using like jQuery, jasmine, (twitter) bootstrap and modernizr. I also have a subfolder called /Site where I am putting my code for the site in multiple files based on the page. (product.js, billing.js, etc.)

Under /Scripts/Site I added a subfolder to /Tests (or Specs) that have the files (product_test.js, billing_tests.js, etc.).

Without having namespaces everything is fine. I have a utility.js file I created with a padLeft helper function. I then used that global padLeft in another .js file. My tests all worked and I was happy. I then decided to figure out the namespace and changed my Scripts/Site/utility.js to look like:

(function (myns, $, undefined) {
    //private property
    var isSomething = true;

    //public property
    myns.something = "something";

    //public method
    myns.padLeft = function (str, len, pad) {
        str = Array(len + 1 - str.length).join(pad) + str;

        return str;
    };


    //check to see if myns exists in global space
    //if not, assign it a new Object Literal
}(window.myns= window.myns|| {}, jQuery ));

Then in my Scripts/Site/Tests/utility_test.js I have

/// <reference path="../utility.js" />

describe("Namespace myns with public property something", function () {
    it("Should Equal 'something'", function () {
        expect(myns.something).toEqual('something');
    });
});

With this extremely simple test I was expecting myns.something to come back with the string value of 'something'.

It doesn't. It comes back undefined.

So, how do I to use javascript namespace across multiple files?

Sorry for the long introduction, but I figured it may help explain the why of me doing it this way. I also put all of this because I'm open to hearing ideas about how this setup is totally wrong or partially wrong or whatever.

Thanks for taking the time to read this question.

UPDATE: SOLVED Thank you all for your help. The most help came from the commenter @T.J. Crowder. I didn't know the jsbin tool existed and after being convinced that the code I put above was put into the tool and the results were right I knew something had to be off in my environment.

The link in the accepted answer also helped me out a lot. After seeing that the syntax and logic was consistent and working I just had to determine what was off about my setup. I'm embarrassed to say it was me passing in jQuery but in my test harness where I was trying to get this to work I wasn't actually using jQuery. This meant the module wasn't actually being loaded - so myns was never set.

Thanks everyone. Hopefully this may be helpful to someone in the future. If you use the above make sure you include the jQuery object. The other option is to not pass in jQuery and remove the $ from the param list.

like image 660
Chad Carter Avatar asked Nov 13 '22 07:11

Chad Carter


1 Answers

Try putting your name space declaration outside of the function call:

myns = window.myns || {};
(function(myns, $, undefined) {
    ...
}(myns, jQuery));

Your existing syntax appears to be completely valid, but breaking that line out may help figure out what's going wrong with your variable scope.

like image 177
Alnitak Avatar answered Nov 16 '22 02:11

Alnitak