I'm writing a bookmarklet using jQuery. It looks like javascript:document.write('<script src="path/to/loader.js"></script>'), and loader.js does the initializing stuffs:
check_the_environment();
document.head.innerHTML='<meta charset=utf-8>';
document.body.innerHTML='(the webpage)';
var jq=document.createElement('script');
jq.src='path/to/jquery.min.js';
document.head.appendChild(jq);
function load_core() {
if(window.$)
eval('(core js code)');
else
setTimeout(load_core,50);
}
load_core();
The loader loads the core javascript code after the jQuery is available.
But sometimes I get this error in my core code:
$(...).on is not a function
It seems that jQuery was still initializing itself although $ variable is setted.
So, I need to wait for jQuery to be completely initialized before the loader loads the core code. How can I do that?
The traditional way of using $(document).ready(...) is infeasible, as jQuery is being loaded after the webpage is ready.
Here is a minimal Python code to check whether the solution is working:
import cherrypy
mod='''
var htmlroot=document.getElementsByTagName('html')[0];
function load_core() {
if(window.jQuery)
jQuery(function(){
alert($(document).on);
});
else
setTimeout(load_core,10);
}
if(!document.head)
htmlroot.appendChild(document.createElement('head'));
var jquery=document.createElement('script');
jquery.src='http://libs.useso.com/js/jquery/2.1.1/jquery.min.js';
document.head.appendChild(jquery);
load_core();
'''
class Website:
#cherrypy.expose()
def mod(self,_time):
return mod
#cherrypy.expose()
def index(self):
return '''Mod'''
cherrypy.quickstart(Website(),'/');
The right and foolproof way would be:
jQuery(function(){
// code
});
Since jQuery may be loaded in noConflict mode the $ var may not have been initialized.
For the sake of productivity the following can also be used to have access to $ var inside the jQuery scope.
jQuery(function($){
// you can use $ without worrying about conflicts now
});
You can check type of $ as below
if(typeof $ == "function"){
//Jquery loaded
}
Related
I am using javascript file and jquery.From my javascript file,I am doing like this:
abc.cde.on({
});
which is calling one widget written in jquery.
abc.cde are namespaces in jquery widget file.
Can anyone please tell how abc.cde.on is calling jquery method without using $ sign before abc.cde
Because cde is already an instance of a jQuery object. You can perfectly store the result of a jQuery selection (or a jQuery widget instance) in an object to reuse it after, see example:
var namespace = {
obj: $('div'),
};
//then you can do:
namespace.obj.on('click', function(){
this.style.color = 'red';
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>CLICK ME</div>
Because the $ is already used in previous reference... I suspect abc was defined something like this:
var abc = $('#abc')
So the $ is already referenced...
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 am using selenium addon as well as jquery in my addon. Due to use of jquery functions with $ being used in selenium throwing function not found error. Removing the Jquery, everything works fine. Using Jquery (ajax call) is must for me. Please suggest how can I make them work together.
One recommended way to solve this kind of conflict is to wrap your javascript code inside a function, and pass jQuery as an argument to this function :
// e.g : turn this code :
$(function(){
$('.my-class').on('click', function(){
$.ajax(...);
});
...
});
// into :
(function($) { // start an anonymous function,
// whose first argument is named '$' ...
$(function(){
$('.my-class').on('click', function(){
$.ajax(...);
});
...
});
}(jQuery)); // and call this function right away,
// passing the jQuery object as first argument
Note that $ is just a shortcut for jQuery :
jQuery('.my-class') and jQuery.ajax(...)
// are exactly the same as :
$('.my-class') and jQuery.ajax(...)
You can also use your own alias :
var $j = jQuery;
If some day you need to mix jQuery with another library which defines a $ variable, you can also use jQuery.noConflict() (example taken from this use case) :
var $j = jQuery.noConflict();
I found the following definition
$.fn.flex = function ( options ) {
var p = this.data("flex"),
opts = options || {};
if (p) return p;
this.each(function () {
p = new Flex( this, opts );
$(this).data("flex", p);
});
return opts.api ? p : this;
};
which defines function flex() in original code.
Unfortunately, it stops defining this function in my environment, i.e. function call causes an error that flex is not a function.
What is critical here for flex being a function?
UPDATE
Sorry, actually I didn't modify anything. I just put this javascript https://github.com/jasonenglish/jquery-flex/ into my environment (Liferay) and the code to run script
<script type="text/javascript">
$(function() {
$(".flex").flex();
});
</script>
caused an error. So I replaced $ to jQuery everywhere as I did before and it is still not working.
UPDATE 2
Hmmm. Error occurs in widget.js from Twitter. Says
TypeError: jQuery(...).flex is not a function
If I rename flex to flex1 everywhere, it says "flex1" is not a function.
Sorry, actually I didn't modify anything. I just put this javascript ... into my environment (Liferay) and the code to run script
Because that's a jQuery plug-in, you need to make sure you include that script after jQuery on the page. So
<script src="/path/to/jquery.js"></script>
<script src="/path/to/the-plugin.js"></script>
If you put them in the other order, the first script will fail because it will try to take the value of the jQuery symbol, which doesn't exist yet, throwing a ReferenceError (in both loose and strict mode).
First of all in $.fn.flex $ and fn are jQuery variables. they are not native to JavaScript. $.fn provided by jQuery to attach method/property to jquery object
I use noConflict() for my source code like this because had lot of problem with including duplicate jquery.js from other source codes in my program:
var $m = jQuery.noConflict();
$m.getJSON(........
problem is that when I call noConflict(), $ will not works. I know I can change $ to JQuery to fix this. but we have lot of custom code from others and this is not possible to change all source codes.
is there a way to recover that? I tried this but not working:
var $ = jQuery.noConflict();
Use a function expression.
(function ($) {
// code using $ for jQuery
}(jQuerysVariable));
If you have access to the other code, wrap it in an IIFE closure that binds jQuery to a parameter called $:
(function($) {
...
})(jQuery);
If you do not have access to the other code, you could try to temporarily set $ to point to your "no-conflict" instance of jQuery:
var _tmp = window.$; // save old value
window.$ = $m; // or window.$ = window.jQuery
// invoke and/or load other code here
...
window.$ = _tmp; // restore previous value