homepage Welcome to WebmasterWorld Guest from 54.197.215.146
register, free tools, login, search, pro membership, help, library, announcements, recent posts, open posts,
Become a Pro Member

Home / Forums Index / Code, Content, and Presentation / JavaScript and AJAX
Forum Library, Charter, Moderator: open

JavaScript and AJAX Forum

    
calling & defining functions using funcName() vs. window['funcName']()
in context of jQuery (doc).ready
sssweb




msg:4533287
 5:25 pm on Jan 4, 2013 (gmt 0)

I'm getting errors in different situations when I don't use the right combination of funcName() & window['funcName'] in defining and calling functions. The errors mainly come up in the context of:

jQuery.noConflict();
jQuery(document).ready(function($) {
});

but crop up more in some cases if calls & defs are in different files.

I've run several tests on the various combinations and found the following patterns.

If the defs ARE w/in (doc).ready, these combinations do not work:
1) window['funcName']() call with funcName() def
2) funcName() call & def (exception: works if both are in the same file)

If the defs are NOT w/in (doc).ready, all combinations work. Unfortunately, the defs must go in (doc).ready because they contain jQuery calls.

Questions:

1) Is there a rule of thumb for using the window[] designation vs. not

2) Is there some way to code it so that it works in every case?

 

Fotiman




msg:4533305
 6:02 pm on Jan 4, 2013 (gmt 0)

Your particular problem is not what you think it is. The problem is that the callback function within ready() is asynchronous. It has nothing to do with whether the functions are defined as window['funcName'] or as function funcName().


Unfortunately, the defs must go in (doc).ready because they contain jQuery calls

jQuery calls do not need to be defined only in the ready method. The ready method just provides an alias of $ as the jQuery object, regardless of whether you've called noConflict. You could alternatively setup your own private alias.

Here's a jsfiddle that demonstrates it:
[jsfiddle.net...]

In the example, $ is defined before jQuery is included. In this example, $ is defined to just take a string and alert it (which is obviously different than what jQuery would do with it). This example demonstrates creating your own alias, but also shows where it's not safe to call a method defined in the ready method.

sssweb




msg:4533315
 6:45 pm on Jan 4, 2013 (gmt 0)

I sort of follow you, but now I get an error even when defining the function outside ready() as you suggest. Here's my code:

jQuery.noConflict();

(function () {
var $ = jQuery;
function test() {
alert("window call / normal def");
$("#test2").fadeOut(1000);
}
})();

jQuery(document).ready(function($) {
window["test"]();
});

I get the error whether the call is w/in ready() or not; the error is: Object doesn't support property or method 'test'.

sssweb




msg:4533323
 7:11 pm on Jan 4, 2013 (gmt 0)

I think I got it; I needed to enclose the whole thing in the anonymous function. Like so:

jQuery.noConflict();

(function () {
var $ = jQuery;
function test() {
alert("window call / normal def");
$("#test2").fadeOut(1000);
}

jQuery(document).ready(function($) {
window["test"]();
});
})();

I'll play around with it and make sure it works in external files, etc; will re-post if I have more questions.

Thanks.

sssweb




msg:4533380
 9:35 pm on Jan 4, 2013 (gmt 0)

[delete]

daveVk




msg:4533415
 11:59 pm on Jan 4, 2013 (gmt 0)

window.test() is the same as window["test"]()

sssweb




msg:4533553
 2:44 pm on Jan 5, 2013 (gmt 0)

There is still some glitch with this. If you change your [jsfiddle.net...] so that funcName0 is NOT defined in window[] format and the calls ARE in window[] format, those functions do not work (I removed the offending funcName1 entirely, since that's the ready() option we're getting rid of; I then made both calls to funcName0). I get the same error reported above (Object doesn't support property or method 'funcName0').

Then there's this: on my site, if I put the funcName0 def OUTSIDE (before) your anonymous function it actually works, but if I do that on your fiddle mock-up, it still doesn't.

I get similar results when using external files (I created an anonymous function for each and put everything inside that, with func defs OUTSIDE ready(), as you suggest.)

Fotiman




msg:4533559
 3:50 pm on Jan 5, 2013 (gmt 0)

Correct. That's because funcName0 only exists within the scope of the anonymous function, whereas defining them using the window[] format explicitly sets them in the window's scope. If you call them using funcName0() as opposed to window['funcName0'](), they would work because of the closure that allows them to be in scope still.

I guess I'm a little confused about what exactly you're trying to accomplish. Is there a reason you want to call the functions using the window[] format?

Also, on the jsfiddle, there are multiple window objects for different frames (which may be why it works on your site but not on the jsfiddle).

Fotiman




msg:4533562
 3:58 pm on Jan 5, 2013 (gmt 0)

Here's an updated jsfiddle, which explicitly sets the funcName0 to the window['funcName0']:
[jsfiddle.net...]
This allows defining the function as:
function funcName0(){...}
but then you also need to set it to the window object.

Again, would be helpful to know exactly what you're trying to accomplish and why.

sssweb




msg:4533577
 4:56 pm on Jan 5, 2013 (gmt 0)

I sort of follow you about the scope thing, but I'm admittedly out of my league on this. I also don't want to waste your time carefully explaining things I'll never understand(!)

That said, I just want code that allows my functions to work in every case (or to at least know the conditions that don't work so I can avoid them). So let me start from scratch and explain what I'm doing, and you can suggest the best approach.

I have a jquery slideshow script (which I use to show text pages, not pic slides) and also several jquery scripts that run text effects on the various pages. All these scripts, with their various functions and calls, must work together. To keep things neat, I thought to write the code generated by each script to a separate file (maybe this is part of the problem; I could print everything to the same file, but I sometimes still get the errors). Everything starts from the slideshow, which runs in a ready() function. (That's the instruction that came with the script. My understanding is that the ready() function ensures that the script won't run until all the page data - e.g. occasional pics, etc. - is loaded; that's what I want.) Also, all func defs & calls in external files run in ready() functions.

Re why I sometimes need the window[] format, in some cases the function name is dynamically generated and per my question in this thread [webmasterworld.com...] -- see page 2, you guys suggested that. I'm starting to think that it's more trouble than it's worth and that I should dump the variable func names, which I can do without. The problem though, as stated in my OP (error #2), is that I sometimes get errors w/o using window[].

What's the best way to go with all this?

I hope you see a clear solution. If not, let me suggest one that might work, and see if you agree: I dump the variable function names and the window[] format, and write everything to the same file and ready() function.

I still want to hear your ideas, since mine requires a fair amount of re-coding. Thanks for your help on this; I really appreciate it.

daveVk




msg:4533652
 3:14 am on Jan 6, 2013 (gmt 0)

Define test outside of other functions (global scope) and you can call it from anywhere with window["test"] or other notations.

If as in these examples test is defined within another function (local scope) it will not work unless you explicitly give it global scope.
window["test"] = function(){...};

If you wish to keep it local and call with [] notation
var dog = {};
dog["test"] = function(){...};

and call as
dog["test"];

sssweb




msg:4533716
 3:31 pm on Jan 6, 2013 (gmt 0)

Yes -- I'm beginning to see how this works. So in my case, if I define & call all my chained events in global scope, and start the chain from my slideshow function, which runs later in a ready() func, everything will be available to it as needed.

Thanks guys.

Fotiman




msg:4533722
 5:24 pm on Jan 6, 2013 (gmt 0)

Here's what I would suggest. Instead of relying on functions in the global scope, it's better to create your own "namespace" and store your functions within it. That way, you only have 1 object in the global scope, which means less chance for conflicts with other scripts. Then you put all of your methods within this one object.

sssweb




msg:4533731
 6:25 pm on Jan 6, 2013 (gmt 0)

I looked that up and see your point. Unless I missed something though, it involves renaming everything to work in the namespace. That's more than I want to do right now and probably above my skill level. Unless there's a simple way to do this by say, adding something at the start (and maybe also end) of every file, while leaving the basic func defs & calls alone, I'll defer this to later when I can bring on a professional programmer to upgrade the code. As of now, there's just this one group of scripts and I haven't seen any conflicts.

But thanks for the heads up on it; I'll definitely put it on my list for future upgrades.

Fotiman




msg:4533831
 12:15 am on Jan 7, 2013 (gmt 0)

Also, all func defs & calls in external files run in ready() functions

That's probably the main problem. Don't put the func defs in ready() calls, otherwise you can't be sure what order those defs will be created in. Instead, put the function definitions outside of the ready statements, and the calls to those functions within the ready.

sssweb




msg:4533942
 1:41 pm on Jan 7, 2013 (gmt 0)

Yes, I see that now. I'm re-coding that; will post if there's still problems.

Thanks again.

sssweb




msg:4533959
 2:45 pm on Jan 7, 2013 (gmt 0)

Well, the functions all run now, but I can't run jquery in them. Since the functions are defined outside jQuery(document).ready(function($){...}); I precede them on the page with:

var $ = jQuery;

But jquery commands in the functions only run if I put that statement INSIDE the function. I thought declaring it outside makes it global, and therefore available in the function.

Also, can I declare this globally in one place (instead of at the top of every js file) so that it's always available?

sssweb




msg:4534001
 3:59 pm on Jan 7, 2013 (gmt 0)

The only way it works with 'var $ = jQuery;' at the top of the page is if I wrap that statement and all of the functions in an anonymous function per Fotiman's [jsfiddle.net...]

But that brings me back to the original problem of having to define it using window[].

Is that my only option?

Fotiman




msg:4534002
 4:03 pm on Jan 7, 2013 (gmt 0)

Let me ask this... are you loading another library such that you need the noConflict? If so, you might consider eliminating that other library (rewriting that code to use jQuery instead), as loading multiple libraries is generally pretty heavy.


I thought declaring it outside makes it global, and therefore available in the function

It does. But when noConflict is run, your global $ will be replaced. This is another reason why having your own namespace would be helpful.

Your scenerio sounds like the following:
1. $ is defined by some other library as something other than jQuery
2. jQuery is loaded and $ is set to jQuery
3. noConflict resets $ back to previous definition
4. Your global functions use $, assuming that $ == jQuery
5. ready() executes and gives a $ == jQuery within it's callback function

I can't think of a good way around this problem, but here are a few options.

1. Create a global variable "$$" and set that to jQuery, then replace all instances of $ in your scripts with $$ (fairly easy to do with any text editor). Alternatively, replace every instance of $ with "jQuery".

2. Modify your functions to take a jQuery object as a parameter:
function funcName($) {...}
Then when you call those functions from ready(), just pass in $

sssweb




msg:4534019
 4:50 pm on Jan 7, 2013 (gmt 0)

I'm using jQuery & jQueryUI (w/some basic plug-ins). Besides that, there's just the text effect scripts; but I don't think they qualify as libraries (they all run on jQuery). There's no MooTools or script.aculo.us or anything.

You're right that it's an issue with the '$' var only; I ran alerts on that and on a generic var -- the generic reads fine, but '$' is "undefined".

I get that regardless of whether I use noConflict() on the func def page. But strangely, if I also remove noConflict() from my call file, I get this for '$':

function(a,b){return new e.fn.init(a,b,h)}

Could the problem be due to the fact that I already use your suggestion #2 in my call file? My slideshow, which starts the whole sequence, runs inside:

jQuery(document).ready(function($){...});

and I call it with:

$("#id")....

Also, in the functions I want to run in external files (the ones with the problems we're discussing), I'm using $("#id2").... for my jQuery commands. That's why I need 'var $ = jQuery;' in the first place.

Am I doing something wrong?

sssweb




msg:4534051
 6:20 pm on Jan 7, 2013 (gmt 0)

Okay, I just discovered that if I delete noConflict() AND var $ = jQuery; from all files, everything works fine. (This is the same setup that gives the "strange" alert value for $: "function(a,b){return new e.fn.init(a,b,h)}" -- I now see that that's probably just a reference to my jQuery library. I was so surprised by the alert that I didn't notice that the code ran fine after I dismissed the alert.)

Anyway, my question now is how to work around the noConflict(), or should I dump it altogether. I think it's there mainly as a precaution in case I add libraries later, which I don't plan to do as of now.

Or do you see a better solution now that we know what's going on?

Fotiman




msg:4534073
 7:11 pm on Jan 7, 2013 (gmt 0)

There's no MooTools or script.aculo.us or anything

In that case, you shouldn't need the noConflict() at all. If you remove that, then $ should be available to all your functions, assuming they are called after jQuery has been loaded (for example, called in the ready() method).
but '$' is "undefined"

I think it depends on when you try to look at it. If you're looking at it before jQuery is loaded, then that makes sense.

Do a [jsfiddle.net...] just with:

I did, and it works as expected. Are you seeing something different?

Based on everything you said, I think that if you remove the noConflict, and you don't try setting $ to anything, then you should be able to do this:
<script src="jquery.js"></script>
<script src="external-1.js"></script>
<script src="external-2.js"></script>
<script src="external-3.js"></script>

Then in your external files, your functions should have access to $ without having to do anything special.

sssweb




msg:4534120
 9:20 pm on Jan 7, 2013 (gmt 0)

Everything seems to be working now. Just to be sure, is this still the correct ready() syntax to use without noConflict():

jQuery(document).ready(function($) {...});

Also, just to help me see how it works, how does the script now know that $ = jQuery w/o that statement in there?

Re the [jsfiddle.net...] when I run it with just:

var $ = jQuery;
alert($);

in the js block, and with jQuery library loaded, I get an alert with the following:

function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
return new jQuery.fn.init( selector, context, rootjQuery );
}

Fotiman




msg:4534130
 10:22 pm on Jan 7, 2013 (gmt 0)


is this still the correct ready() syntax to use without noConflict():

jQuery(document).ready(function($) {...});

That should still work, though you could omit the $ in the parameter list and write it as:
jQuery(document).ready(function() {...});
or alternatively:
$(document).ready(function() {...});


how does the script now know that $ = jQuery w/o that statement in there?

The jQuery library creates the global $ variable. When it does that, it stores a reference to whatever the global variable $ was assigned to previously (if anything), and that's how it resets it when you call noConflict.


in the js block, and with jQuery library loaded, I get an alert with the following:

function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
return new jQuery.fn.init( selector, context, rootjQuery );
}

That is correct. Note, that is the non-minified version of the code. When minified, you'll see this:

function(a,b){return new e.fn.init(a,b,h)}

Which is functionally identical, but with spaces/comments removed and shortened variable names.

sssweb




msg:4534313
 2:56 pm on Jan 8, 2013 (gmt 0)

Is there a preference for the ready() syntax?

I still find that, in global scope, func calls usually return 'undefined' unless the function is defined BEFORE the call -- tricky sometimes when working with linked functions and external files. I suppose namespacing is the only way around that?

Fotiman




msg:4534316
 3:13 pm on Jan 8, 2013 (gmt 0)


Is there a preference for the ready() syntax?

If noConflict is not called, then generally you would do something like this:
$(document).ready(function() {...});


func calls usually return 'undefined' unless the function is defined BEFORE the call

Correct. You must always define a function before calling it. But it shouldn't be complicated, and external files shouldn't impact it (unless they're being loaded asynchronously).

sssweb




msg:4534340
 4:28 pm on Jan 8, 2013 (gmt 0)

It gets tricky if I have one series of text effect functions in one file, and a series of different functions in another file, and the script alternates between the two types of text effect. Then there's a chicken & egg setup where each must go before the other at different times.

As of now though, that's hypothetical. In the vast majority of cases, the initial trigger is the slideshow, which is in the ready(), and doesn't fire until after ALL the globals load -- so it shouldn't be a problem. I'll just have to keep an eye out if the other situation comes up.

daveVk




msg:4534474
 10:25 pm on Jan 8, 2013 (gmt 0)

It gets tricky if I have one series of text effect functions in one file, and a series of different functions in another file, and the script alternates between the two types of text effect. Then there's a chicken & egg setup where each must go before the other at different times.


If you define all functions outside of ready function, and execute only on ready, situation does not occur.

sssweb




msg:4534632
 1:22 pm on Jan 9, 2013 (gmt 0)

Yes -- I was referring to events not triggered by my slideshow, which is in the ready() function. But I see now that I can always add an initial trigger in the ready() function, if needed.

So I think this issue is resolved. Thanks again for all the help -- you guys are life-savers.

Global Options:
 top home search open messages active posts  
 

Home / Forums Index / Code, Content, and Presentation / JavaScript and AJAX
rss feed

All trademarks and copyrights held by respective owners. Member comments are owned by the poster.
Home ¦ Free Tools ¦ Terms of Service ¦ Privacy Policy ¦ Report Problem ¦ About ¦ Library ¦ Newsletter
WebmasterWorld is a Developer Shed Community owned by Jim Boykin.
© Webmaster World 1996-2014 all rights reserved