Javascript modules, passing jQuery when it may not be loaded - javascript

I'm learning the module pattern for javascript in order to tidy up my code and reduce the need for a long 'global' javascript file.
As a consequence of this, I have a top level 'namespace' module, and a utility module in the same file. The utility module has some functions that require jquery, and others that do not.
On lightweight pages that use no jQuery, I don't want to load the library (I have a very good reason for not doing so).
The problem arises when jQuery is passed as a parameter to the module as in the following:
MODULE.vars = (function (variables,$) {
variables.cdn = undefined; //global for clientside cdn
variables.version = undefined; //global for clientside cdn version
variables.isTouchScreen = undefined; //global for touchscreen status
//Check if jquery exists, if so patch the jquery dependent functions
if ($) {
$(document).ready(function () {
variables.isTouchScreen = $('html').is('.touch');
});
}
return variables;
}(MODULE.vars || {}, jQuery));
The code stops on pages that I don't load jquery, stating that jQuery is undefined - fair enough. If I change the last line to:
}(MODULE.vars || {}, jQuery || false));
the code still complains that jQuery is undefined. I thought, perhaps erroneously, that if jQuery was undefined, it would be passed as undefined in this instance and instead take up the value false (which logic dictates wouldn't be necessary anyway).
How do I get around this problem when jQuery may or may not be present? I attempted to put the following at the top of the script:
var jQuery = jQuery || false;
thinking that this would then take up the value of jQuery if it was loaded. It works in modern browsers with this, but IE8 complains as it gets set to false even if jQuery is being loaded first on a page.
The scripts are all loaded in the correct order in the html, jQuery first, then my module afterwards.
When checking for the cause, IE8 returns $ as an object and jQuery as false. If i do not set the above line in the script, jQuery returns as the same object as $.
Sadly I have to cater for IE8 as well, so how do I get around this issue of the optional presence of jQuery?
Edit: This is only a snippet of the module and there are other functions that depend on jquery, but simply won't get implemented if jquery is not available

I seem to have found an answer that works after I worked out how to implement elanclrs suggestion - I put the following at the top of my modules:
var jQ = jQ || false;
if (typeof jQuery !== 'undefined') {
jQ = jQuery;
}
Then in my module, I pass jQ instead of jQuery.
The reasoning behind the answer was pointed at in this question: Error when passing undefined variable to function?

Related

Very weird jQuery error

So I had code that was working properly on my site:
$("#usr").load("somepage.php",{var1:var1,var2:var2});
But ever since I changed some code in the navigation bar, jQuery has been acting really strangely. The first major problem was that this line:
var w = $(window).width();
returns the error: object [global] has no method "width()"
And that didn't seem to matter, as all elements on the page functioned with that error (as if it was still being executed, because elements were still being placed)...but then I came to the page that implemented the first line of code, and I ran into the following error:
Cannot call method "load()" of null
Sure enough, I checked the console, and $("#usr") returns null, but I can see the HTML line in the page with the inline id of usr.
This causes a problem because I need to load data from that page for the page to function properly. But it gets even stranger. I thought I would just try a plain post request and take the data and use document.getElementById("usr").innerHTML = ... as a substitute, but I get the following error from this line:
$.post("somepage.php",{var1:var1,var2:var2},function(data){
document.getElementById("usr").innerHTML = data;
});
Error:
Uncaught TypeError: Object function $(el){if(!el)return null;if(el.htmlElement)return Garbage.collect(el);if([window,document].contains(el))return el;var type=$type(el);if(type=='string'){el=document.getElementById(el);type=(el)?'element':false}if(type!='element')return null;if(el.htmlElement)return Garbage.collect(el);if(['object','embed'].contains(el.tagName.toLowerCase()))return el;$extend(el,Element.prototype);el.htmlElement=function(){};return Garbage.collect(el)} has no method 'post'
What the heck is going on with jQuery?
I'm importing 1.8.2 from googleapis
That sounds a lot like you're loading Prototype or MooTools or something as well as jQuery, and so Prototype/MooTools/whatever is taking over the $ symbol.
If that's what's going on, and you need the other library, you can use jQuery.noConflict(). Then you either use the symbol jQuery instead of $ for your jQuery stuff, or you put all of your jQuery code into a function that you pass into jQuery.noConflict and accept $ as an argument, like so:
// Out here, $ !== jQuery
jQuery.noConflict(function($) {
// In here, $ === jQuery
});
Or you can just do it yourself:
// Out here, $ !== jQuery
jQuery.noConflict();
(function($) {
// In here, $ === jQuery
})(jQuery);
ready also passes the jQuery object into the function, if you're already using ready.

Adding jQuery to a 3rd party page fails

I am trying out a few things, and among those I tried to insert jquery on a site, namely, http://www.tesco.com/wine.
For some reason, I was not able to able access jQuery even though I was able to successfully append a new script tag to the body element. Also, the page seems to have a window.$ function that I tried to delete with delete window.$. This, seems to return false for me. How do you make something undeleteable?
Here is the code I used to append the jQuery script to the document:
var s = document.createElement('script');
s.src = "http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js";
document.body.appendChild(s)
It is working on other pages.
After discussing this in JavaScript chat, Tim Stone discovered that the JS on the page adds its own implementation of Object.prototype.extend - which breaks the jQuery script. To fix it (but potentially break another script on the page), you can delete that before adding jQuery:
delete Object.prototype.extend;
var s = document.createElement('script');
s.src = "http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js";
document.body.appendChild(s)
$ is already defined on that page with the following function declaration:
function $(A){return document.getElementById(A)}
It is not uncommon to alias document.getElementById() with $() — in fact, Firebug and WebKit's developer tools do this in their console.
It is not deletable, because it is declared as a function statement and not an object property. While delete may work in some browsers, it shouldn't and won't in others. That being said, I was able to override the function with a simple assignment:
$ = function () {}
When jQuery loads, it creates the jQuery namespace and aliases this namespace with $. Therefore, if something else on the page is overriding $, you can still use jQuery().
If $ is already defined, you can always use jQuery instead.

How can I use jQuery 1.5.2+ on a Firefox addon?

At first I made a function that received a parameter and returned jQuery such as:
function getjQuery(window)
{
/*jquery code*/(window);
return window.jQuery;
}
But then I got an email form the review and they told me I have to use jQuery file with the original file name and completely unmodified.
I started to search for an alternative and found this solution, but there is no way it work.
jQuery object is created, but I can't find any elements. $("#id").length is always 0. With the previous method it was always found.
My current code (which doesn't work)
AddonNameSpace.jQueryAux = jQuery;
AddonNameSpace.$ = function(selector,context) {
return // correct window
new AddonNameSpace.jQueryAux.fn.init(selector,context||contentWindow);
};
AddonNameSpace.$.fn =
AddonNameSpace.$.prototype = AddonNameSpace.jQueryAux.fn;
AddonNameSpace.jQuery = AddonNameSpace.$;
The jQuery file is loading on my browser.xul overlay:
<script type="text/javascript" src="chrome://addon/content/bin/jquery-1.5.2.min.js" />
Am I loading in the right place?
How can I use jQuery to modify the content on a page (HTML) with the original jQuery file, is it even possible?
You need pass the e.originalTarget.defaultView on the second parameter on jquery..
If you don't jquery will use window.document, which is the window.document from the xul.
Use
gBrowser.addEventListener("DOMContentLoaded", function (e) {
$("#id", e.originalTarget.defaultView).length
}, true);
instead of
$("#id").length;
And, for avoid conflicts with other extensions don't use script in the xul page, use MozIJSSubScriptLoader.
Components.classes["#mozilla.org/moz/jssubscript-loader;1"]
.getService(Components.interfaces.mozIJSSubScriptLoader)
.loadSubScript("chrome://youraddon/content/jquery-1.5.2.min.js");
If you use this method, you load jquery only when you need, avoiding memory leak.
The preferred way to load it is with mozIJSSubScriptLoader so you don't collide with other's extensions. I'm not sure why you're having problems, I can use jQuery in my addon like $("#id").hide() with no additional code (although from the sidebar, now browser.xul).
Either way, this blog post provides a pretty good guide and even has an example xpi to download.

Can I void all JavaScript calls to $

I need some scripts inside an existing site's scripts.js.
This site has been online for ages, and I can not touch the scripts file.
I am including it standardly in another page. There are numerous jQuery calls in the scripts file. The place I include it does not have jQuery.
I want to void all $() type things. I tried this...
$ = function() { };
before I included scripts.js and it didn't seem to work. I am still getting errors like
$(document) is undefined
Is there a way to void all these jQuery calls?
Thanks
Even if you do get that working, you'll still have problems because the code was written with the assumption that jQuery was present. Yes, you can avoid $ is null or not defined errors on lines like this:
$('div.foo');
But there's no point in just writing that line: there will always be actions on the returned object:
$('div.foo').html('blah');
After the NOP jQuery function, you'll get a "html" is not a function error, and so on. The only way you could do it would be to fill out a skeleton of every possible jQuery method, making sure each one returns itself when appropriate.
...or just rewrite it properly...
try
window.$ = function(selector, context) {alert('eating the calls to $');}
in your file that you're including before the scripts.js file. This is how it's defined in jquery so should take care of the selector syntax.
You may need to define other overrides to cater for the $.method() type calls tho
Well, it's no surprise that $(document) is undefined, since you're not returning a value from your placeholder function. Thus, things like $(document).ready(function(){}); will naturally be errors.
Basically, if I understand right, you need $ to be a function that does nothing and returns another object where calling any member function does nothing. Further, calling member functions of $ itself (e.g. $.ajax()) should have the same behavior.
You can do this with __noSuchMethod__, which is unfortunately non-standard:
window.$ = function()
{
var doNothingObj = new (function()
{
this.__noSuchMethod__ = function()
{
return doNothingObj;
}
})();
return doNothingObj;
};
window.$.__noSuchMethod__ = window.$;
This will allow arbitrary chains:
$(document).ready(function(){});
$("#foo").animate().animate();
$.ajax({ url: "file.html"});
etc.
Of course, a much saner solution is to refactor the code that uses jQuery.

jquery element not defined, but it used to skip it

I recently transferred a site to a new host. Reloaded everything, and the javascript that worked fine before is breaking at an element it can't find. $('#emailForm') is not defined.
Now, the #emailform isn't on the page, but it wasn't before either, and JS used to skip this and it would just work. Not sure why this is happening. Any clues
Here is the site I am having the prblem:
http://rosecomm.com/26/gearwrench/
jQuery will return an empty jQuery object from $('#emailForm') if there isn't an element with the id='emailForm'.
One of the following is likely true:
You forgot to include jQuery - therefore $ is undefined.
There is another library included that uses $ - in which case you can wrap your code in a quick closure to rename jQuery to $
The Closure:
(function($){
// $ is jQuery
$('#emailForm').whatever();
})(jQuery);
You could console.log(window.$,window.jQuery); in firebug to check for both of these problems.
You have mootools-1.2.2-core-yc.js installed as well, and it is conflicting with jQuery.
http://docs.jquery.com/Using_jQuery_with_Other_Libraries
$(document).ready(function() {
(function($){
// bind 'myForm' and provide a simple callback function
$('#emailForm').ajaxForm(function() {
var txt=document.getElementById("formReturn")
txt.innerHTML="<p>Thank You</p>";
});
...
$(document).ready is being called against the moo tools library instead of jQuery.
I'm not sure why it would be skipped before, but to avoid the error, wrap the statement(s) that reference $('#emailForm') in an if statement that checks to see if it is present:
if ( $('#emailForm').length ) {
// code to handle $('#emailForm') goes here...
}

Categories