Possible to load jQuery only inside closure? - javascript

I don't think this can be done, though I know requirejs can do something similar, and I was wondering if this might be possible outside of require.
I'm writing a piece of SaaS JavaScript code that will most likely need jQuery to run cross browser. Some sites have it, some don't, but I don't want to stick jQuery on the window object if they aren't using it. Though I could individually create alternatives for everything I use jQuery for... I was wondering if there is a way I can load jQuery only for use inside my closure. Is this possible?

When you load the standard release of jQuery, by default jQuery assigns itself to the global names jQuery and $. If you load your version of jQuery before your closure file within the page, then within your closure do
var $ = jQuery.noConflict(true);
It will undo whatever modifications your version of jQuery did to the global object.
It is worth noting, however, that this produces a race condition. If any events or timeouts fire between the time that your jQuery file loads and your closure calls jQuery.noConflict(true) they will accidentally use the version of jQuery that you loaded.
An alternative is to edit the jQuery file that you are using to include a call to jQuery.noConflict(true) at the bottom of the jQuery file. You can assign the result to an arbitrary name that no one else would ever think to use, like "abcRandomNumberHere". Then you can retrieve your instance of jQuery from that global name within your closure assigning it to a local variable named jQuery and/or $ and delete the global reference at that time.
// Your jQuery file on your server
// ...
// End of file:
someRandomGlobalName = jQuery.noConflict(true);
// The file that contains your closure:
(function() {
var $, jQuery;
$ = jQuery = someRandomGlobalName;
delete window.someRandomGlobalName;
// Your code that uses jQuery here
} ());
This is a rough approximation of what RequireJS does to keep jQuery out of the global namespace. Recent versions of jQuery have built-in code that detects the existence of a script loader like RequireJS and rather than assigning to global names jQuery passes a reference to itself into RequireJS and leaves the global object untouched. That way RequireJS contains the reference to jQuery internally, but the global.requirejs variable is modified instead.
Creating your own non-conflicting global name for your jQuery version and your closure to "rendezvous" on is analogous to RequireJS' functionality. The name RequireJS uses is the "global name": requirejs.s.contexts._.jQuery (not exactly, but something like this).

Call jQuery.noConflict(true) and it will re-assign $ and jQuery to wherever it was.
Then, you can pass the reference returned by the above expression into your closure.
(function(jQuery) {
})(jQuery.noConflict(true));

Yes, calling jQuery.noConflict(true) will completely remove anything that jquery added from the global namespace reverting it back to what it was previously allowing for conflicting libraries and/or multiple versions of jQuery.
<script src="jquery.min.js"></script>
<script>
(function($){
$("el").doSomething();
})(jQuery.noConflict(true));
</script>

Related

Can I load jQuery dynamically to a local variable rather than to window?

I am developing a widget to implement a "Zopim" like live chat. To modify the DOM of the page my widget will live in I'd like to use jQuery, but I want to do that without polluting the global namespace of the host page.
How can I achieve that?
Use jQuery.noConflict(true)
jQuery.noConflict(true) will remove all jQuery variables form global scope.
https://api.jquery.com/jquery.noconflict/
Steps
Check if window.jQuery is defined. If it is and matches version you need (jQuery.fn.jquery) use that version.
Otherwise Load jQuery and use noConflict(true) to assign to another variable and maintain any existing $ in page

jQuery alias for script specific

Wordpress ships jQuery in safe mode, this is very awesome, but a 3rd party script that I must use uses the $ alias, so there's a way of alias $ to jQuery only for that script ? (can't edit the script since it's 3rd party)
wrap the initialisation of the plugin in an IIFE
(function($){
$('.some').pluginUsingDollarAsJQuery();
})(jQuery)
As per the help pages for plugin authorship:
The $ variable is very popular among JavaScript libraries, and if you're using another library with jQuery, you will have to make jQuery not use the $ with jQuery.noConflict(). However, this will break our plugin since it is written with the assumption that $ is an alias to the jQuery function. To work well with other plugins, and still use the jQuery $ alias, we need to put all of our code inside of an Immediately Invoked Function Expression, and then pass the function jQuery, and name the parameter
Which basically boils down to the fact that whoever has written the plugin you're using has not done it right.
Writing a plugin like this:
$.fn.doSomething = function(){
// whatever
}
Will make it not compatible with anyone using jQuery in noConflict mode. It should be wrapped in an IIFE like this:
(function($){
$.fn.doSomething = function(){
// whatever
}
})(jQuery)
If your plugin is the former style, ditch it.
Jamiec's answer is the clean solution which should be used if you have access to the code, but in case you do not have access to it, there is a dirty solution.
You can reassign $ to jQuery just before the script is loaded. So when the script is initializing, $ === jQuery.
To do it when the script is inline in the DOM, just open a script tag for the reassignment before :
<script>$=jQuery;</script>
<script src="external_script"></script>
If you load dynamically the script (ex : jQuery.getScript), you can reassign just before calling the async function :
window.$ = jQuery;
jQuery.getScript('external_source');
WARNING : this method can break your script if window.$ was used elsewhere. It may also not work if the script is loaded asynchronous if, meanwhile, another script reassign $ to something else.

assets pipeline control coffee script's closures

I have 2 simple coffee scripts and assets pipeline. I obtained:
(function() {
window.App.Test_widget = {...}
}).call(this);
(function() {
$.widget("ui.Test_widget", window.App.Test_widget);
$(document).ready(function() {...});
}).call(this);
but I want 1) merge closures 2) add closure parameter
(function($) {
var App;
App.Test_widget = {...}
$.widget("ui.Test_widget", App.Test_widget);
$(document).ready(function() {...});
})(jQuery);
I cant google a way of implementing this
UPD:
1) I dont want to place each file in different closures. I want to control this
2) I dont want to put anything in window if it is possible
ANSWER is simply: "use bare option. for sprockets see commit"
If you want that level of fine-grained control over output, you'll have to write your JavaScript yourself rather than allowing CoffeeScript to do it for you. I say that as an advocate of CoffeeScript: If you use it, you have to accept certain conventions that go along with it, such as the wrapper that gives each file its own scope. You lose the freedom to concatenate files however you want in order to share variables across files.
It's worth mentioning, however, that
In CoffeeScript 1.2.0+, the wrapper is added only when necessary. At least in your first file, that's not the case. (Edit: I was mistaken about this; this feature existed in 1.1.3 but disappeared before 1.2.0)
Writing $ = jQuery at the top of a function is semantically equivalent to having an argument named $ and passing in jQuery as the value of that argument. So you need only put $ = jQuery at the top of each of your CoffeeScript files in order to use jQuery in noConflict mode.
I think what you're describing is a deferred...you want to do something after your two closures finish? If so then look into jQuery 1.5 deferred infrastructure.

Mixing javascript and jquery within namespace

Was having trouble a few weeks ago getting jquery to run in firebug (esp on drupal sites). Apparently the issue was that Drupal was grabbing the $ variable, so I got a little namespace snippet (function($)...(Jquery)); that reclaimed the $. I have been using the namespace in firebug but geting inconsistent results, especially when mixing pure javascript and Jquery within the namespace. I understand that all Jquery is javascript and they work together, but looking at samples I see some weird variations in the way people deploy this namespace. As a general question but also specifically within Firebug context, is there any need to place javascript in any particular relation to namespaced Jquery (inside the namespace, function calls inside, function out, or any other convention)?
Thanks
If you meant preventing the $ from being reclaimed, there is no convention but there is a way. other frameworks also use the $ name. anything declared later to use $ will take over $. however, you can prevent it or get around it.
jQuery offers a lot of ways to prevent it via its noConflict() method. but my preferred method is just wrap them in a function. jQuery also uses the jQuery namespace. $ is a shorthand alias, a very common one too. so functions like $.each() is also jQuery.each(). what crazy framework uses jQuery as its namespace anyway?
an example of wrapping in a function is like this:
(function($){
//inside here, "$" is jQuery
}(jQuery)); //pass "jQuery"

Defining a scope for JQuery variables, different js - single page

I have 2 js on a single page. In one of the js I am doing var jQuery = $.noConflict(true); and after that using all the jQuery methods using jQuery object, like jQuery("#div").hide();
In another js, I am using the traditional $ variable & accessing the jQuery methods as $("#div").hide();
When on a page I use either of the 2 js', things work fine. However, when I include both, the $ in the second js seems to be overwritten by jQuery. for example, in js 2 I can no longer do $("#div").hide() but if I use jQuery instead of $, it works fine - jQuery("#div").hide();!
Why am I experimenting this is because the first div will be distributed to different websites as a plugin, and the second js could be the Jquery written by that website developer.
Please help me figure out where am I going wrong..
Thanks.
You're using noConflict, which releases jQuery's hold on $. Doesn't matter if it's in separate scripts, since it's the same global environment.
In the script where you want to use $, define that variable inside your .ready() handler.
jQuery(function($) {
$('foo').bar();
});
The easiest way to solve this is to use a pattern that plugin authors employ.
(function($) {
// Use $ safely within the function
})(jQuery); // Passes in jQuery object
This is function is created and invoked immediately, and at the same time allows you to pass a variable into the scope of the function. Using this, you can carry on referring to $ in your code and not worry about overwriting it or conflicting.
The jQuery documentation advises this pattern
Files do not have scope, you dereferenced $ with noConflict for your entire page. Anything

Categories

Resources