views:

73

answers:

4

I'm trying to cobble together a php style include function for javascript. The route I'm taking is through a XMLHttpRequest. The included file will load, but the functions in that file aren't available as their scope is limited to the function that is calling them.

I came across this article which achieves a similar goal, but requires the coder to specify which functions they require in advance, while I would like to simply include a file and automatically add the functions the window object.

Here's my progress

function twinkle(){

    getXMLHTTPObj("twinkle/test.js");

    // A simple function inside test.js
    includedFunc();

}


// XMLHttp Stuff lifted from he Apple tutorial

var req;
function getXMLHTTPObj(url) {
    req = false;
    // branch for native XMLHttpRequest object
    if(window.XMLHttpRequest && !(window.ActiveXObject)) {
        try {
            req = new XMLHttpRequest();
        } catch(e) {
            req = false;
        }
    // branch for IE/Windows ActiveX version
    } else if(window.ActiveXObject) {
        try {
            req = new ActiveXObject("Msxml2.XMLHTTP");
        } catch(e) {
            try {
                req = new ActiveXObject("Microsoft.XMLHTTP");
            } catch(e) {
                req = false;
            }
        }
    }

    if(req) {
        req.onreadystatechange = processReqChange;

            // Set to False so javascript waits for the included functions 
            // to become available 
        req.open("GET", url, false);
        req.send("");
    }

    return req;
}

function processReqChange() {
    // only if req shows "loaded"
    if (req.readyState == 4) {
        // only if "OK"
        if (req.status == 200) {
            eval(req.responseText);
        } else {
            alert("There was a problem retrieving the XML data:\n" +
                req.statusText);
        }
    }
}

I'm considering creating an index of functions inside each included file that can be iterated over when the file is included, but that's not really an elegant solution.

Any ideas? Is there some javascript property or function I can access to get a list of functions in the file?

+1  A: 

Instead of loading the JavaScript file via AJAX, why not create a <script> tag and insert that into the page? That will allow the JavaScript to be parsed in the global scope. Take a look at how Scriptaculous' require function works

Josh
For some reason, I really don't like that approach. I don't know why, and it's completely my personal preference, but this way feels neater to me.
gargantaun
+1  A: 

Change the way you declare your functions and it should solve the scoping issue. Instead of:

function add(a, b) 
{                     
    return a + b;
} 

do this:

var add = function(a, b) 
{                     
    return a + b;
}   
RedFilter
close! I went with window.includedFunc = function(){ ... } which solves that problem perfectly.
gargantaun
@gargantaun: You should post that as an answer
Josh
If you add that to your answer, I can accept it. (is it a faux pas to accept slightly right answers?)
gargantaun
@gargantaun: the only downside there is that all global functions have to be declared that way. It seems silly to do it that way just because you "don't like" the DOM method, which will work correctly without having to change the required file.
Andy E
@josh: I feel bad whenever I have to answer my own questions, especially so soon after just asking it. If OrbMan doesn't edit his answer, you can take it.
gargantaun
@Andy: You're probably right, but for the project I have in mind, which will basically be a big library of Javascript objects, this method creates a nice visual clue as to what sort of file I'm working on. Javascript lacks this sort of visual distinction when it comes to OOP.
gargantaun
My method always worked for me when using Prototype, perhaps it was doing some magic behind the scenes. I can't verify your method right now, so go ahead and post your own answer if you wish.
RedFilter
+1  A: 

It's simple enough to use the DOM to add the required script:

function include(jsFile)
{
    var sEl  = document.createElement("script");
    sEl.type = "text/javascript";
    sEl.src  = jsFile;
    document.getElementsByTagName("head").appendChild(sEl);
}

Browsers will even download this file asynchronously, and script elements have an onload event that works in most (all?) popular browsers so you can also add a callback function if you like. The obvious downside is that functions wouldn't become available to the current script until the file is downloaded and parsed.

Andy E
And if the onload gives you issues, append to the end of each script a function which calls some custom onload handler, i.e: `scriptFinishedLoading('nameofThisScriptFile.js');`
Josh
I mentioned this in another comment... but there's just somethign about that method that I don't like. It may be irrational. But OrbMan's answer put me on the right track anyway, so problem solved.
gargantaun
@gargantaun: it seems more irrational to me to change the source in the included file to use `window.funcName = function () {}` for every globally declared function.
Andy E
@Andy: Sorry, I'm repeating myself across two answers here... but you're right, my way is probably the wrong way to go in most instances, but for the project that I'm working on, which is a library of Javascript Objects, this method provides a convenient visual clue as to what type of file I'm working on, which javascript generally lacks. And above all, I now know it *is* possible to do it this way. Wether it pans out for the best or not is another discussion.
gargantaun
@gargantaun: If you're doing it that way, I would look into namespacing. This involves creating a global object variable in the main file and the included files add classes, methods and properties to that namespace when they're evaluated. It's pretty much the same as doing `window.funcName = function () {}`, you're just using your own namespace instead of polluting the `window` object.
Andy E
@Andy: That's exactly what I was looking for. I just didn't know it yet. Cheers.
gargantaun
+1  A: 

OrbMan pointed me in the right direction on this one, but the solution to this particular method of including Javascript files requires the functions be defined differently; like this

window.myFunction = function(){ 

    alert("Hey There!") 

}

A potential upside to this is that any functions in the included file that are declared the normal way are encapsulated so they are only available to the window.functions from that file... as far as I can tell.

gargantaun
Have a +1 whilst you wait 24 hours to accept your answer ;-)
Andy E