I'm building a widget that depends on jquery being loaded - I'm using the following to load it and my code:
(function () {
var jqueryVersion = (window.jQuery !== undefined) ? window.jQuery.fn.jquery.charAt(0) + window.jQuery.fn.jquery.charAt(2) : 0;
var jQuery;
/******** Called once jQuery has loaded ******/
function scriptLoadHandler() {
jQuery = window.jQuery.noConflict(true);
main();
}
/******** Load jQuery if not present *********/
if (parseInt(jqueryVersion) < 17) {
var script_tag = document.createElement('script');
script_tag.setAttribute("type", "text/javascript");
script_tag.setAttribute("src", "//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js");
script_tag.onload = scriptLoadHandler;
script_tag.onreadystatechange = function () { // Same thing but for IE
if (this.readyState === 'complete' || this.readyState === 'loaded') { scriptLoadHandler(); }
};
document.getElementsByTagName("head")[0].appendChild(script_tag);
} else {
jQuery = window.jQuery;
main();
}
function main() {
//my code goes in here
//leaving blank for now because I still get error
}
})();
I got most of that from here: http://alexmarandon.com/articles/web_widget_jquery/
I need jquery 1.7 or higher because I use the .on() method. When I run this on a page using jquery that is older than 1.7 I sometimes get errors in IE that lead me to believe there is a conflict with either the old version of jquery or some other js on the page. Some errors:
SCRIPT5007: Unable to get property 'forceInt' of undefined or null reference
SCRIPT5007: Object expected
SCRIPT5007: Unable to get property 'easing' of undefined or null reference
SCRIPT438: Object doesn't support property or method 'on'
These errors go away if I change
jQuery = window.jQuery.noConflict(true);
to
jQuery = window.jQuery.noConflict();
Am I doing something wrong?
Your problem might be caused by the fact that the 'handler' is called twice.
http://msdn.microsoft.com/en-us/library/ie/hh180173(v=vs.85).aspx
Also, taken from http://api.jquery.com/jQuery.noConflict/
"If necessary, you can free up the jQuery name as well by passing true
as an argument to the method. This is rarely necessary, and if you
must do this (for example, if you need to use multiple versions of the
jQuery library on the same page), you need to consider that most
plug-ins rely on the presence of the jQuery variable and may not
operate correctly in this situation."
Related
I keep receiving the following error from the browser console when loading my script into my Magento store. All that it is listening for is an onclick event on a div yet I receive this error:
"Uncaught TypeError: Cannot read property 'click' of null."
The script works in JSfiddle so I'm really not quite sure why it isn't working. I've tried enclosing it within a $( document ).ready() as well but I receive the same error.
Code:
var step = 0;
var deviceType = "";
var modelType = "";
function showGen(){
$('.phoneTypes').css("display", "none");
if (deviceType == "Samsung"){
$('.sphoneGens').css("display", "block");
}
if (deviceType == "iPhone"){
$('.iphoneGens').css("display", "block");
}
if (deviceType == "iPad"){
$('.ipadGens').css("display", "block");
}
}
// Pick Device Type
$('.choicelabel').click(function(){
deviceType = $(this).children('input').val();
showGen();
});
//Pick Device Gen
$('.choiceType').click(function(){
modelType = $(this).children('input').val();
//$(".iphoneGens").css("display", "none");
console.log(deviceType);
console.log(modelType);
$(this).parents(".row").hide();
});
Any help debugging this issue will be greatly appreciated.
TL;DR:
jQuery( document ).ready(function( $ ) {
// Code using $ as usual goes here.
// And document is ready too
});
What's the issue?
Prototype.js was loaded after jQuery and was overwrite global $ symbol.
How can we deal with it?
You still have jQuery global to use. Just use it everywhere, where you want to use $.
// Pick Device Type
jQuery('.choicelabel').click(function(){
deviceType = jQuery(this).children('input').val();
showGen();
});
//Pick Device Gen
jQuery('.choiceType').click(function(){
modelType = jQuery(this).children('input').val();
//jQuery(".iphoneGens").css("display", "none");
console.log(deviceType);
console.log(modelType);
jQuery(this).parents(".row").hide();
});
You can also to define some shorthand for simplify it:
jQ = jQuery;
Common best practice for cases like this is to use IIFE wrap for your code:
;(function($){ // see note-1
// Use $ here! It's jQuery now
$(function(){
// be sure DOM was loaded before work with it(ex: binding events)
});
})(jQuery);
This adds nothing to global scope and achieves what we need.
You always can inject some other libraries(prototypejs?) with alias what you want to this IIFE.
note-1: Semicolon before IIFE protects javascript from previous expression with missed semicolon to be interpreted as function call.
jQuery itself provides shorthand for this case:
jQuery( document ).ready(function( $ ) {
// Code using $ as usual goes here.
// And document is ready too
});
That site isn't using jQuery, it's using prototypejs
I have the following javascript function that prevents form submission if all required fields are not complete and is part of a form I am creating using Google Apps Scripts. Note that the #submitbutton is actually a regular button and Google Apps Scripts forces strict javascript. The script works fine on chrome, but when I test it on Safari or Firefox, it doesn't appear to be running. Am I using a method that only works on Chrome? Am I missing something here?
I get the following errors in Safari:
Uncaught TypeError: undefined is not a function (evaluating '(1, $)('#submitbutton')') and Uncaught Strict mode does not allow function declarations in a lexically nested statement.
Firefox gives a similar issue: Uncaught in strict mode code, functions may be declared only at top level or immediately within another function 2699307207-maestro_htmlapp_bin_maestro_htmlapp.js:84:360 and Uncaught TypeError: $ is not a function
<script type="text/javascript">
$('#submitbutton').on('click', function() {
$(this).val("Submitting...");
//check for required fields
var emptyFields = $('[required]').filter(function() {
$(this).removeClass("warning");
if ($(this).val().length === 0){
$(this).addClass("warning")
return true
} else {
return false
}
});
if (emptyFields.length === 0) {
$(this).prop('disabled', true);
document.getElementById('incompleteWarning').style.display = 'none';
document.getElementById('bePatient').style.display = 'inline';
google.script.run.withSuccessHandler(fileUploaded).uploadFiles(this.parentNode);
} else{
$(this).val("Submit Application")
document.getElementById('incompleteWarning').style.display = 'inline';
document.getElementById('incompleteWarning').style.color = 'red';
}
});
</script>
jsfiddle here: https://jsfiddle.net/hofresre/
Note that the jsfiddle doesn't use the google.script, but replaces it with this.parentNode.submit()
Any help is greatly appreciated.
Per comments:
Line 84 of maestro_htmlapp_bin_maestro_htmlapp.js:84:360:
function ys(a){for(var b=[],c=0;c<a.length;++c){var d=a[c];b[c]=Mn(d)?(new String(d)).toString():d}return b}var As=[vh,"[object Object]"];var Bs=["alert",ts(function(a){return alert(a)},16,[4]),"confirm",ts(function(a){return confirm(a)},16,[4]),"prompt",ts(function(a,b){return prompt(a,b)},16,[4,4])];var Cs=window.console&&window.console.error?function(a){window.console.error(a)}:void 0,Ds=window.console&&window.console.info?function(a){window.console.info(a)}:void 0,Es=window.console&&window.console.log?function(a){window.console.log(a)}:void 0,Fs=window.console&&window.console.warn?function(a){window.console.warn(a)}:void 0,Gs=["console.debug",ts(window.console&&window.console.debug?function(a){window.console.debug(a)}:void 0,16,[4]),"console.error",ts(Cs,16,[4]),"console.info",ts(Ds,16,[4]),
I guess you know that browser don't support web functionalities the same way. We know that google always focalize their web library and their support firstly for chrome browser.
When you just have this error:
functions can only be declared at top level or immediately within another function
You must not put a function declaration inside any other block, like an if-statement or for-loop; cause any block scope that use curly braces: try-catch-finally, if-else if-else, for, switch, and ES6 also define new feature that utilize block scope such as class.
you can't: "use strict" { Function bar(){/****/} }
Therefore, independents solutions that i can provide are:
Find if there is a version of script (here google script or JQuery) (which is recent) where this problem have been solved.
You can also comment "use strict" in the corresponding script (for example in google script).
Make show that you first include google script and JQuery before the other js scripts.
Try to use non minified script library because something (an example which append with JQuery 1.11) it's the cause of the problem.
Before trying previous solutions, maybe this modified code can work:
<script type="text/javascript">
var trySubmission = function() {
$(this).val("Submitting...");
//check for required fields
var emptyFields = $('[required]').filter(function() {
$(this).removeClass("warning");
if ($(this).val().length === 0){
$(this).addClass("warning")
return true
} else {
return false
}
});
if (emptyFields.length === 0) {
$(this).prop('disabled', true);
document.getElementById('incompleteWarning').style.display = 'none';
document.getElementById('bePatient').style.display = 'inline';
google.script.run.withSuccessHandler(fileUploaded).uploadFiles(this.parentNode);
} else{
$(this).val("Submit Application")
document.getElementById('incompleteWarning').style.display = 'inline';
document.getElementById('incompleteWarning').style.color = 'red';
} ;
}
$('#submitbutton').on('click', trySubmission ) ;
</script>
What mode are you loading the HTML as from the GS file?
When in SandboxMode.NATIVE the error occurs in SandboxMode.IFRAME things seem to work
Here is some test code for a GS file
function doGet(e) {
var html= HtmlService.createTemplateFromFile("test.html");
return html.evaluate().setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
...and the HTML as test.html
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script>
function myFunction() {
if (jQuery) {
// jQuery is loaded
console.log( "Loaded" );
} else {
// jQuery is not loaded
console.log( "Not Loaded" );
}
$("#message").html("Something happened.");
}
$(document).ready(myFunction);
</script>
<p id="message">Nothing happened. </p>
The following JavaScript works correctly in all browsers except IE 7 and 8:
if (typeof django != 'undefined') {
console.log('Django admin loaded');
var jQuery = django.jQuery;
}
This code is on top of a JavaScript file that is loaded both inside Django's admin interface and on our public pages. Django's admin loads its own jQuery, so we use that one preferably ...
However, IE 7 and 8 executes the variable assignment inside this if statement even if the condition (typeof django != 'undefined') is false. At the same time, the console.log() is not executed :-/ Removing the var keyword, the same code works perfectly also in IE 7 and 8:
if (typeof django != 'undefined') {
console.log('Django admin loaded');
jQuery = django.jQuery;
}
But why? That doesn't make any sense, does it?
ALL browsers will do this. It's called hoisting.
function test() {
if( false) {
var abc;
}
alert(abc); // expect ReferenceError, get undefined
}
Since you're defining jQuery, you probably want that as a global variable, so window.jQuery = django.jQuery should do just fine.
There is no such thing as block scope within javascript (please see here for more details of JS scoping: What is the scope of variables in JavaScript?).
Your initial code doesn't make much sense anyway - if you are trying to set the global jQuery variable, then your code should be:
if (typeof django != 'undefined') {
console.log('Django admin loaded');
jQuery = django.jQuery;
}
What you are seeing is probably a difference with how IE7 and 8 handle their JS scopes.
If you define the var keyword then you need to do like this:
if (typeof django != 'undefined') {
console.log('Django admin loaded');
var jQuery = django;
django.jQuery; // or django = django.jQuery
}
My team and I want to maintain a low cost for switching from Zepto to another framework or native browser calls (we only target WebKit) while using it.
What are the tactics of keeping track of the places in the code where Zepto is used?
Is there anything better that maintaining a Readme list of methods used?
How would you do it?
jQuery: You can use noConflict to assign some nice, unique name to the jQuery function (perhaps jQuery itself as that's built-in, but if that's a pain something else readily distinguished from other things, like $jq or some such — noConflict returns the jQuery function so you can do that, e.g. var $jq = jQuery.noConflict();).
Zepto: Despite claiming a "jQuery-compatible syntax," it doesn't appear to support noConflict per se. However, it looks like if $ is already defined on the window object, it will leave it alone, because of this line:
'$' in window || (window.$ = Zepto);
So define $ before loading Zepto and then only use Zepto in your code (or assign something to it that's equally unique, like $jq or $zt, etc. — e.g., var $zt = Zepto;).
In either case: Then search your code for those if/when you need to find those bits.
Beyond searching for $ and specific methods, you could identify which methods are in use by logging their usage in running code.
The following code will log the function used and the stack trace every time you make a jQuery call but not log any internal calls made by jQuery.
<script>
(function(){
var insideJQuery = false;
function replaceMethod(obj, method, prefix) {
var oldMethod = obj[method];
if(typeof oldMethod !== "function")
return;
obj[method] = function() {
var externalCall = !insideJQuery;
insideJQuery = true;
var output = oldMethod.apply(this, arguments);
if(externalCall) {
console.log(prefix + method + ' called');
console.trace();
insideJQuery = false;
}
return output;
}
}
for(var method in $.fn) {
if(method != 'constructor' &&
method != 'init')
replaceMethod($.fn, method, '$.fn.');
}
for(var method in $) {
if(method != 'Event')
replaceMethod($, method, '$.');
}
})();
</script>
The exception of course would be jQuery calls inside jQuery calls like $(document).ready(function(){$('div')});.
Um, you could search for the $ sign?
Every method like parents() will be called on something that was ultimately created with the $ sign. So if you find all instances of $ and trace the use of the resulting variables you'll have everything.
I've built a JavaScript widget that must be embeddable on any third-party site, in any environment. The widget relies on jQuery and jQuery UI. I followed the steps in How to embed Javascript widget that depends on jQuery into an unknown environment to add jQuery in a responsible manner -- works great for embedding jQuery. But when I try to add jQuery UI, it fails. Here's the code:
(function(window, document, version, callback) {
var j, d;
var loaded = false;
if (!(j = window.jQuery) || version > j.fn.jquery || callback(j, loaded)) {
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js";
script.onload = script.onreadystatechange = function() {
if (!loaded && (!(d = this.readyState) || d == "loaded" || d == "complete")) {
callback((j = window.jQuery).noConflict(1), loaded = true);
j(script).remove();
}
};
document.documentElement.childNodes[0].appendChild(script)
}
})(window, document, "1.3.2", function($, jquery_loaded) {
$.getScript('http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.js', function(){
console.log('loaded');
});
});
When I run this, I get the 'loaded' mesage, followed by an error saying that "$ is undefined" on line 15 of jquery-ui.js. But how can $ be undefined when I'm using $.getScript() to load jQuery UI? And why do I see the message 'loaded' before I get the error? According to the jQuery documentation, getScript shouldn't execute the callback until the script has been loaded and executed.
Is there any way I can use this framework to include jQuery UI, or do I need to use a script loader like RequireJS in order to load everything, enforce dependencies, etc.?
By calling .noConflict(1), the same as .noConflict(true), you're deleting jQuery, just remove the 1. The true argument to .noConflict() tells jQuery to remove not only $, but window.jQuery, which jQuery UI is trying to use afterwards, when it loads.
You can test it here, see there are no errors in the console.