Why does the global jQuery object get overwritten after the page loads? - javascript

I'm writing a jQuery extension contained in a self executing function:
(function($) {
// global variables for the purposes of this test
__$ = $;
__$support = $.support;
$.support.abc = "123";
// Setup for my extension goes here.
})(jQuery);
On my test page, I have
<script type="text/javascript" src="jquery-1.5.2.js"></script>
<script type="text/javascript" src="myplugin.js"></script>
<script type="text/javascript">
$(function() {
console.log(__$ === $); // false
console.log(__$support === $.support); // false
console.log($.support.abc); // undefined
});
</script>
Why does this happen? I have no other scripts or jQuery plugins that might overwrite the jQuery object.
I haven't been able to find what code in the jQuery source itself overwrites the jQuery object after the document is ready. Any ideas?
If there's no way to avoid this, what would be the correct procedure for defining new properties on the jQuery.support object that can still be accessed after the document is ready?
EDIT: I omitted a critical part of my test code that inadvertently reevaluated the jQuery source -- and explains why this issue was happening. See my answer below.

Something is wrong because I get the correct output.

Wow, I feel stupid.
My test code (the part that I hadn't posted in the question) was intentionally calling jQuery.ajax() on jquery-1.5.2.js (since this is a reasonably big file for testing progress events). However, I had forgotten that unless one manually sets the dataType option to something other than script, jQuery will evaluate any JavaScript that's retrieved by jQuery.ajax().
So jQuery was evaluating a new copy of its own source code, and window.jQuery was therefore getting overwritten.

Related

React - Using external js from CDN

Sorry, I put this again since the old post got merged into some post that doesn't relate to my question ... I'm new to React and trying to convert a php website into react components. However, in old website there are some function in pure jquery and from CDSNJS. The external javascripts function are not binding well with my component and I cannot figure out how to. Please can anyone give me some advice.
Case 1:
I got a an external function like this:
;(function ($) {
/* Global variables */
var prty, flickr;
$.fn.flickrGallery = function(flickrID) {
//Defaults settings
var opts = $.extend({}, {
Key:prty.settings["Key"],
Secret:prty.settings["Secret"],
User:prty.settings["User"],
PhotoSet:flickrID,
Speed:400,
navigation:1,
keyboard:1,numberEl:1 });
//Setup
prty.Setup($(this), opts);
}; //End FN
prty = {
.... Internal code
};
})(jQuery);
And this is my component's code:
async componentDidMount() {
//$('#gallery').flickrGallery(2); // Not work
//const el = ReactDOM.findDOMNode(this.display); Not work
//$(el).vectorMap({map: 'world_mill_en'});
//$(el).flickrGallery(2);
//const el = ReactDOM.findDOMNode(this.domRef); Not work
//window.$('#addSupModal').modal('show')
//$(el).flickrGallery(2);
window.$(this.productIntro).flickrGallery(2); Not work
}
Every time I run, an error like this appears:
Unhandled Rejection (TypeError): window.$(...).flickrGallery is not a function
Case 2:
Beside the case above, I'm also using a lib from CDNJS
<!-- jQuery 1.8 or later, 33 KB -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<!-- Fotorama from CDNJS, 19 KB -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/fotorama/4.6.4/fotorama.css" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/fotorama/4.6.4/fotorama.js"></script>
I have tried including these links into index.html but the same error as above happens when I run ... Please help
Try to access the flickrGallery function via window.jQuery instead of window.$.
The plugin add the flickrGallery function to jQuery. In most of the time, jQuery should be the same as $. However, in some cases, multiple version of jQuery are loaded and jQuery may no longer be equals to $.
The following suggestions were told to be not solving the problem. I will keep them below in case someone find it useful.
It looks like your react component script is executed and rendered before the external scripts is being executed. There are many causes to it and one of the reasons is the ordering of your script tags.
In the document head, make sure the ordering of your script tag is as follow.
<script src="path/to/external/library.js"></script>
<script src="path/to/your/react/script.js"></script>
These script tags do not have the defer nor async attribute, suggesting they should be downloaded, parsed and executed in order. The external script is executed first.
In other cases, where there are defer, async, etc. attributes are in the script tag, you can understand the order of execution by reading this cheat sheet.
If you are using plugin which adds its functionality to some global variable, your bundler may tree-shake it away because it does not detect any usage of its exports and thinks the module is not needed. In this case, you have to add side effect import (Doc).
In your entry module, add this at the very top:
import 'some-jquery-plugin'

How to include javascript file only once

I want to give clients an HTML block they can include in their site, and this HTML will contain some table and image, plus a javascript that will make manipulations over the HTML block.
so I give them the HTML :
<a data-theme="1" data-srv="http://localhost:50987/" class="block1" href="http://myserver/payment/Details">outer information</a><script type="text/javascript" src="http://myserver/Scripts/checkout.js"></script>
in checkout.js I have included JQuery if no Jquery exists in document and do manipulation over the element $('a.block1') ... the problem is when someone puts this block of HTML more then once over the same page, I want that the client will not call "checkout.js" more then once,
I've tried declaring global var inside "checkout.js" and check if it's exists, it works good to stop doing the same manipulation more then once but I want to stop the call to JS al together .
Javascript runs after it loads, you can't stop the JS running, if it is referenced multiple times. It won't be loaded multiple times, so the overhead of it running again is basically nil.
To stop the behavior of the javascript happening again, just put the check at the top level of the file, put the rest of the file in the conditional, and write to a global variable to make sure you don't run again.
if (window._your_unique_id === undefined) {
window._your_unique_id = true;
// the rest of your javascript
}
that will mean nothing in the script runs. You can still define whatever you like in that if statement, though if you define functions and variables in there, you may have to explicitly put them on the window object, because they'll otherwise be local (but then, it is bad practice to have anything implicitly defined global anyway, so it shouldn't make any difference if your code is well structured).
Just deploy your code as a module.
Ie.
(function(window){
if(window.CheckoutModule) return;
// now you're certain there's no global module loaded
var CheckoutModule = window.CheckoutModule = {};
// you can, ie, add a jQuery check here.
if('undefined' != typeof jQuery) {
// do your jQuery thing here.
}
return ;
})(window, jQuery);

Function Undefined: Must a javascript function be defined within the same file?

I've got a file notifications.js containing one event bound to an element, and a function updateNotification(). This function uses jQuery to update certain elements on the page when a JSON object is passed as a parameter.
The problem:
I'm attempting to call this function within the page (via <script> tags), however rather than calling it, it breaks the page. I did some digging around within the Chrome Developer Console (not sure of the name), and an error is flagged:
/pleaseshare/views/install/:50 Uncaught ReferenceError:updateNotification is not defined
However, when I pan within the console, I can clearly see the file notifications.js listed under scripts, and the function is defined there. If I define the function within the current scope (e.g. the line above the call), it works fine.
What I've tried
The function contains some javascript that requires jQuery, so I've attempted both with and without encasing it in $(document).ready( function() {});, with neither seeming to have any affect.
I'm pretty stumped.
For good measure, here's a link to show the structure of my javascript and html: http://snippi.com/s/znk6xe9
Any help in figuring out why this is happening, or explanations of why javascript functions cannot be called cross-file (although I'd hope this isn't the case), would be greatly appreciated ;)!!
A function cannot be called unless it was defined in the same file or one loaded before the attempt to call it.
A function cannot be called unless it is in the same or greater scope then the one trying to call it.
You code looks like the structure should work, but is clearly a reduced test case that has been reduced to the point where it won't.
Got it working. The issue was definitely multi-faceted, but I figured it out.
First off the use of RequireJS had an impact on updateNotification(), in that it couldn't be called cross-file, and was therefore considered undefined. I assume this because of how RequireJS loads files, and I'll look into the documentation later (and post an edit if I find anything relevant).
Secondly, updateNotification() would again be considered undefined when encased within jQuery's DOM ready loader $(document).ready(function(){}). However updateNotification() contains executions which require jQuery, so I had to encase the contents of the function in $(document).ready(function(){}).
This is an issue very unique to RequireJS/jQuery, hence why in most use cases this wouldn't occur.
Side note: The tags are edited to reflect this.
you need to import your script into your page:
<script type="text/javascript" language="javascript" src="path/to/notifications.js"></script>
This needs to be added above the <script> tag that calls updateNotification()
Functions do not need to be declared in the same file. In fact, avoiding having every declaration dumped into the global namespace is usually a concern in JavaScript.
In the sample code in the link you provided, updateNotification is declared as a global, so there should not be a scoping problem.
However, in the same sample, you don't show notifications.js being included. You need to import it using a <script></script> element and that element must come before the script element that includes the call to updateNotification. You also must include jQuery before notifications.js, since it uses jQuery. So you need something like:
<body>
// One or two elements
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript" src="notifications.js"></script>
<script type="text/javascript">
$(document).ready( function() {
var json = {status : 'ok', message: 'Hello'};
updateNotification(json);
});
</script>
// All other elements
</body>

RequireJS Flawed By Example?

Looking into RequireJS but unlike Head.JS which downloads in undetermined order but evaluates in a determine order, RequireJS seems different
Normally RequireJS loads and evaluates scripts in an undetermined order.
Then it shows how to prefix order! to the script names for explicit ordering etc..
Then in the examples:
require(["jquery", "jquery.alpha", "jquery.beta"], function($) {
//the jquery.alpha.js and jquery.beta.js plugins have been loaded.
$(function() {
$('body').alpha().beta();
});
});
So if jquery.alpha is downloaded and evaluated before jquery then surely this would cause a problem? Forgetting any client code usage such as function body above, if like most plugin they attach to jQuery.fn then at stage of evaluation then jQuery will undefined in this scenario.
What am I missing here?
RequireJS is not designed to load plain javascript, but to load defined modules. The module format looks something like:
define(['a', 'b'], function(a, b) {
return { zzz: 123 };
});
The important thing to note is that all of the module code is inside an anonymous function. So if the file is run in an arbitrary order, it doesn't matter, because all it does is register the module. The module code is then run in dependency order, with the return value becoming the module object, which is passed as a parameter to code that uses the module.
If you are trying to load plain files, this will not work correctly for you. There is the order plugin to force load order in that case.
It should be noted that that example uses the custom made version of "requirejs and jquery" packaged together, which I believe means that jquery will always be available first.
If you have problems, you can always wrap your plugins within a module definition and make sure they depend on jquery themselves, again ensuring the order is correct:
/* SPECIAL WRAPPING CODE START */
define(['jquery'], function(jQuery) {
// .... plugin code ....
/* SPECIAL WRAPPING CODE END */
});
You are correct, without something to aid in the order an exception will occur. The good news is RequireJS has an Order plug-in to help in this.
I'm currently evaluating RequireJS...
And Here Is An Example of One of My Files:
The 'order!' command will load files for you sequentially. You can (then) use the callback to load other (support) files.
<script src="Loaders/RequireJS/requireJS.js" type="text/javascript"></script>
<script src="Loaders/RequireJS/order.js" type="text/javascript"></script>
<script type="text/javascript">
require(["Loaders/RequireJS/order!././Includes/JavaScript/jQuery/Core/jquery-1.3.2.js",
"Loaders/RequireJS/order!././Includes/JavaScript/jQuery/Core/jquery.tools.min.js",
"Loaders/RequireJS/order!././Includes/JavaScript/jQuery/ThirdPartyPlugIns/jquery.tmpl.js"], function() {
require(["././Includes/JavaScript/jQuery/jGeneral.js",
"././Includes/JavaScript/jQuery/autocomplete.js",
"././Includes/JavaScript/jQuery/jquery.ErrorWindow.js",
"././Includes/JavaScript/jQuery/jquery.ValidationBubble.js",
"././Includes/JavaScript/jQuery/jquery.Tootltip.js",
"././Includes/JavaScript/jQuery/jquery.Extensions.js",
"././Includes/JavaScript/jQuery/jquery.Toaster.js"], null);
require(["././Includes/JavaScript/jQuery/ThirdPartyPlugIns/jquery.dimensions.js",
"././Includes/JavaScript/jQuery/ThirdPartyPlugIns/jQuery.Color.Animations.js",
"././Includes/JavaScript/jQuery/ThirdPartyPlugIns/jquery.corners.min.js",
"././Includes/JavaScript/jQuery/ThirdPartyPlugIns/jquery.tipsy.js",
"././Includes/JavaScript/jQuery/ThirdPartyPlugIns/jquery.numberformatter-1.1.0.js",
"././Includes/JavaScript/jQuery/ThirdPartyPlugIns/jquery.tipsy.js"], null);
});
</script>
In All Honesty:
I'm looking at various asynchronous resource-loaders and I'm having a hard-time finding one that does everything I need. I'm also finding the documentation in each one lacking.

Why is my JavaScript function sometimes "not defined"?

I call my JavaScript function. Why do I sometimes get the error 'myFunction is not defined' when it is defined?
For example. I'll occasionally get 'copyArray is not defined' even in this example:
function copyArray( pa ) {
var la = [];
for (var i=0; i < pa.length; i++)
la.push( pa[i] );
return la;
}
Function.prototype.bind = function( po ) {
var __method = this;
var __args = [];
// Sometimes errors -- in practice I inline the function as a workaround.
__args = copyArray( arguments );
return function() {
/* bind logic omitted for brevity */
}
}
As you can see, copyArray is defined right there, so this can't be about the order in which script files load.
I've been getting this in situations that are harder to work around, where the calling function is located in another file that should be loaded after the called function. But this was the simplest case I could present, and appears to be the same problem.
It doesn't happen 100% of the time, so I do suspect some kind of load-timing-related problem. But I have no idea what.
#Hojou: That's part of the problem. The function in which I'm now getting this error is itself my addLoadEvent, which is basically a standard version of the common library function.
#James: I understand that, and there is no syntax error in the function. When that is the case, the syntax error is reported as well. In this case, I am getting only the 'not defined' error.
#David: The script in this case resides in an external file that is referenced using the normal <script src="file.js"></script> method in the page's head section.
#Douglas: Interesting idea, but if this were the case, how could we ever call a user-defined function with confidence? In any event, I tried this and it didn't work.
#sk: This technique has been tested across browsers and is basically copied from the Prototype library.
I had this function not being recognized as defined in latest Firefox for Linux, though Chromium was dealing fine with it.
What happened in my case was that I had a former SCRIPT block, before the block that defined the function with problem, stated in the following way:
<SCRIPT src="mycode.js"/>
(That is, without the closing tag.)
I had to redeclare this block in the following way.
<SCRIPT src="mycode.js"></SCRIPT>
And then what followed worked fine... weird huh?
It shouldn't be possible for this to happen if you're just including the scripts on the page.
The "copyArray" function should always be available when the JavaScript code starts executing no matter if it is declared before or after it -- unless you're loading the JavaScript files in dynamically with a dependency library. There are all sorts of problems with timing if that's the case.
My guess is, somehow the document is not fully loaded by the time the method is called. Have your code executing after the document is ready event.
Verify your code with JSLint. It will usually find a ton of small errors, so the warning "JSLint may hurt your feelings" is pretty spot on. =)
A syntax error in the function -- or in the code above it -- may cause it to be undefined.
This doesn't solve your original problem, but you could always replace the call to copyArray() with:
__args = Array.prototype.slice.call(arguments);
More information available from Google.
I've tested the above in the following browsers: IE6, 7 & 8B2, Firefox 2.0.0.17 & 3.0.3, Opera 9.52, Safari for Windows 3.1.2 and Google Chrome (whatever the latest version was at the time of this post) and it works across all browsers.
If you're changing the prototype of the built-in 'function' object it's possible you're running into a browser bug or race condition by modifying a fundamental built-in object.
Test it in multiple browsers to find out.
This has probably been corrected, but... apparently firefox has a caching problem which is the cause of javascript functions not being recognized.. I really don't know the specifics, but if you clear your cache that will fix the problem (until your cache is full again... not a good solution).. I've been looking around to see if firefox has a real solution to this, but so far nothing... oh not all versions, I think it may be only in some 3.6.x versions, not sure...
Solved by removing a "async" load:
<script type="text/javascript" src="{% static 'js/my_js_file.js' %}" async></script>
changed for:
<script type="text/javascript" src="{% static 'js/my_js_file.js' %}"></script>
Use an anonymous function to protect your local symbol table. Something like:
(function() {
function copyArray(pa) {
// Details
}
Function.prototype.bind = function ( po ) {
__args = copyArray( arguments );
}
})();
This will create a closure that includes your function in the local symbol table, and you won't have to depend on it being available in the global namespace when you call the function.
This can happen when using framesets. In one frame, my variables and methods were defined. In another, they were not. It was especially confusing when using the debugger and seeing my variable defined, then undefined at a breakpoint inside a frame.
I'm afraid, when you add a new method to a Function class (by prtotyping), you are actually adding it to all declared functions, AS WELL AS to your copyArray(). In result your copyArray() function gets recursivelly self-referenced. I.e. there should exist copyArray().bind() method, which is calling itself.
In this case some browsers might prevent you from creating such reference loops and fire "function not defined" error.
Inline code would be better solution in such case.
I think your javascript code should be placed between tag,there is need of document load

Categories

Resources