JQuery code selects only one element instead of multiple ones - javascript

The problem:
I execute this script on the My Saves page of Google Images but it selects only one element.
According to the JQuery Documentation:
Note: most jQuery methods that return a jQuery object also loop through the set of elements in the jQuery collection — a process known as implicit iteration. When this occurs, it is often unnecessary to explicitly iterate with the .each() method:
Which means that my code should work on all the elements which have the specified class. But unfortunately, it is carrying out all of the work only on the first element:
$('.col-cv-select').click();
I have also tried using explicit iteration with the .each() method but the browser console throws an error when I use this script:
$('.col-cv-select').each(function (index, element) { element.click(); });
Uncaught TypeError: $(...).each is not a function(…)
I am sure that the page uses JQuery because the first code works quite well, but only selects one element.
Reproducing the problem:
I think you need to be logged in to Google before proceeding.
Go to Google and search for 'unicorns' (or anything you prefer).
Click on the Images tab.
Select any image. Click on Save in the Pop-up.
Repeat the above step with another image.
Next visit the My Saves page.
Fire up your browser console and try the codes above.
Test Environment:
Opera 37.0.2178.43 - Stable (Since it's based on Chromium, hopefully, using Chrome will yield similar behavior)
Windows 8.1 Pro
Hope you can help me out :) Thanks in advance.

Just because the $ variable is defined doesn't mean that jQuery is loaded on the page.
When you run $('.col-cv-select') on that page you're actually running document.querySelector('.col-cv-select') which by design only returns one element.
The reason you're seeing the TypeError about $(...).each not being a function is because the return value of the first function is a DOM node, not a jQuery object.
You can inject the jQuery library into the page by running this code in the developer console: (Taken and adapted from this page)
(function() {
// more or less stolen form jquery core and adapted by paul irish
function getScript(url) {
var script = document.createElement('script');
script.src = url;
var head = document.getElementsByTagName('head')[0],
done = false;
// Attach handlers for all browsers
script.onload = script.onreadystatechange = function() {
if (!done && (!this.readyState ||
this.readyState == 'loaded' ||
this.readyState == 'complete')) {
done = true;
script.onload = script.onreadystatechange = null;
head.removeChild(script);
}
};
head.appendChild(script);
}
getScript('https://code.jquery.com/jquery.min.js');
})();
Once you execute that code, the $ variable will be aliased to jQuery and you'll be able to use its .each method and everything else that comes with it.
Just remember that once you reload the page the jQuery library will be unloaded, and to load it again you'll need to re-run the code above.

You need to import jquery into your chrome browser before testing
use the following block of code, before calling your test code
var jq = document.createElement('script');
jq.src = "https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js";
document.getElementsByTagName('head')[0].appendChild(jq);
// ... give time for script to load, then type.
jQuery.noConflict();

Related

Including dynamic script in jQuery [duplicate]

Any idea why the piece of code below does not add the script element to the DOM?
var code = "<script></script>";
$("#someElement").append(code);
The Good News is:
It's 100% working.
Just add something inside the script tag such as alert('voila!');. The right question you might want to ask perhaps, "Why didn't I see it in the DOM?".
Karl Swedberg has made a nice explanation to visitor's comment in jQuery API site. I don't want to repeat all his words, you can read directly there here (I found it hard to navigate through the comments there).
All of jQuery's insertion methods use
a domManip function internally to
clean/process elements before and
after they are inserted into the DOM.
One of the things the domManip
function does is pull out any script
elements about to be inserted and run
them through an "evalScript routine"
rather than inject them with the rest
of the DOM fragment. It inserts the
scripts separately, evaluates them,
and then removes them from the DOM.
I believe that one of the reasons jQuery
does this is to avoid "Permission
Denied" errors that can occur in
Internet Explorer when inserting
scripts under certain circumstances.
It also avoids repeatedly
inserting/evaluating the same script
(which could potentially cause
problems) if it is within a containing
element that you are inserting and
then moving around the DOM.
The next thing is, I'll summarize what's the bad news by using .append() function to add a script.
And The Bad News is..
You can't debug your code.
I'm not joking, even if you add debugger; keyword between the line you want to set as breakpoint, you'll be end up getting only the call stack of the object without seeing the breakpoint on the source code, (not to mention that this keyword only works in webkit browser, all other major browsers seems to omit this keyword).
If you fully understand what your code does, than this will be a minor drawback. But if you don't, you will end up adding a debugger; keyword all over the place just to find out what's wrong with your (or my) code. Anyway, there's an alternative, don't forget that javascript can natively manipulate HTML DOM.
Workaround.
Use javascript (not jQuery) to manipulate HTML DOM
If you don't want to lose debugging capability, than you can use javascript native HTML DOM manipulation. Consider this example:
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "path/to/your/javascript.js"; // use this for linked script
script.text = "alert('voila!');" // use this for inline script
document.body.appendChild(script);
There it is, just like the old days isn't it. And don't forget to clean things up whether in the DOM or in the memory for all object that's referenced and not needed anymore to prevent memory leaks. You can consider this code to clean things up:
document.body.removechild(document.body.lastChild);
delete UnusedReferencedObjects; // replace UnusedReferencedObject with any object you created in the script you load.
The drawback from this workaround is that you may accidentally add a duplicate script, and that's bad. From here you can slightly mimic .append() function by adding an object verification before adding, and removing the script from the DOM right after it was added. Consider this example:
function AddScript(url, object){
if (object != null){
// add script
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "path/to/your/javascript.js";
document.body.appendChild(script);
// remove from the dom
document.body.removeChild(document.body.lastChild);
return true;
} else {
return false;
};
};
function DeleteObject(UnusedReferencedObjects) {
delete UnusedReferencedObjects;
}
This way, you can add script with debugging capability while safe from script duplicity. This is just a prototype, you can expand for whatever you want it to be. I have been using this approach and quite satisfied with this. Sure enough I will never use jQuery .append() to add a script.
I've seen issues where some browsers don't respect some changes when you do them directly (by which I mean creating the HTML from text like you're trying with the script tag), but when you do them with built-in commands things go better. Try this:
var script = document.createElement( 'script' );
script.type = 'text/javascript';
script.src = url;
$("#someElement").append( script );
From: JSON for jQuery
It is possible to dynamically load a JavaScript file using the jQuery function getScript
$.getScript('http://www.whatever.com/shareprice/shareprice.js', function() {
Display.sharePrice();
});
Now the external script will be called, and if it cannot be loaded it will gracefully degrade.
What do you mean "not working"?
jQuery detects that you're trying to create a SCRIPT element and will automatically run the contents of the element within the global context. Are you telling me that this doesn't work for you? -
$('#someElement').append('<script>alert("WORKING");</script>');
Edit: If you're not seeing the SCRIPT element in the DOM (in Firebug for example) after you run the command that's because jQuery, like I said, will run the code and then will delete the SCRIPT element - I believe that SCRIPT elements are always appended to the body... but anyway - placement has absolutely no bearing on code execution in this situation.
This works:
$('body').append($("<script>alert('Hi!');<\/script>")[0]);
It seems like jQuery is doing something clever with scripts so you need to append the html element rather than jQuery object.
Try this may be helpful:
var fileref=document.createElement('script');
fileref.setAttribute("type","text/javascript");
fileref.setAttribute("src","scriptAnalytics.js");
document.getElementsByTagName("head")[0].appendChild(fileref);
I want to do the same thing but to append a script tag in other frame!
var url = 'library.js';
var script = window.parent.frames[1].document.createElement('script' );
script.type = 'text/javascript';
script.src = url;
$('head',window.parent.frames[1].document).append(script);
<script>
...
...jQuery("<script></script>")...
...
</script>
The </script> within the string literal terminates the entire script, to avoid that "</scr" + "ipt>" can be used instead.
Adding the sourceURL in the script file helped as mentioned in this page:
https://blog.getfirebug.com/2009/08/11/give-your-eval-a-name-with-sourceurl/
In the script file, add a statement with sourceURL like "//# sourceURL=foo.js"
Load the script using jQuery $.getScript() and the script will be available in "sources" tab in chrome dev tools
Your script is executing , you just can't use document.write from it. Use an alert to test it and avoid using document.write. The statements of your js file with document.write will not be executed and the rest of the function will be executed.
This is what I think is the best solution. Google Analytics is injected this way.
var (function(){
var p="https:" == document.location.protocol ? "https://" : "http://";
d=document,
g=d.createElement('script'),
s=d.getElementsByTagName('script')[0];
g.type='text/javascript';
g.src=p+'url-to-your-script.js';
s.parentNode.insertBefore(g,s); })();
You don't need jQuery to create a Script DOM Element. It can be done with vanilla ES6 like so:
const script = "console.log('Did it work?')"
new Promise((resolve, reject) => {
(function(i,s,o,g,r,a,m){
a=s.createElement(o),m=s.getElementsByTagName(o)[0];
a.innerText=g;
a.onload=r;m.parentNode.insertBefore(a,m)}
)(window,document,'script',script, resolve())
}).then(() => console.log('Sure did!'))
It doesn't need to be wrapped in a Promise, but doing so allows you to resolve the promise when the script loads, helping prevent race conditions for long-running scripts.
Append script to body:
$(document).ready(function() {
$("<script>", { src : "bootstrap.min.js", type : "text/javascript" }).appendTo("body");
});
Another way you can do it if you want to append code is using the document.createElement method but then using .innerHTML instead of .src.
var script = document.createElement( 'script' );
script.type = 'text/javascript';
script.innerHTML = 'alert("Hey there... you just appended this script to the body");';
$("body").append( script );
I tried this one and works fine. Just replace the < symbol with that \x3C.
// With Variable
var code = "\x3Cscript>SomeCode\x3C/script>";
$("#someElement").append(code);
or
//Without Variable
$("#someElement").append("\x3Cscript>SomeCode\x3C/script>");
You can test the code here.
Can try like this
var code = "<script></" + "script>";
$("#someElement").append(code);
The only reason you can't do "<script></script>" is because the string isn't allowed inside javascript because the DOM layer can't parse what's js and what's HTML.
I wrote an npm package that lets you take an HTML string, including script tags and append it to a container while executing the scripts
Example:
import appendHtml from 'appendhtml';
const html = '<p>Hello</p><script src="some_js_file.js"></script>';
const container = document.getElementById('some-div');
await appendHtml(html, container);
// appendHtml returns a Promise, some_js_file.js is now loaded and executed (note the await)
Find it here: https://www.npmjs.com/package/appendhtml
Just create an element by parsing it with jQuery.
<div id="someElement"></div>
<script>
var code = "<script>alert(123);<\/script>";
$("#someElement").append($(code));
</script>
Working example: https://plnkr.co/edit/V2FE28Q2eBrJoJ6PUEBz

Using javascript to create Jquery link

We have a dynamic adbanner which is loaded onto websites via Google Double Click.
We use some Jquery in the code so as part of the set up we check if a website is running Jquery and if not we use Javascript to add a link to our Jquery file.
This is being done fine however I'm still getting an error "Uncaught ReferenceError: jQuery is not defined" I'd assume this is due to the order things are loading in but I'm not sure how to get around the issue. Everything works fine if you refresh the page the problem only seems to happen on first load.
Also if I open a new browser window and load the page a second time everything works fine.
Here's the code we are using to add the script tags to the head:
if(!window.jQuery)
{
var fm_j = document.createElement('script'); fm_j.type = 'text/javascript';
fm_j.src = 'js/jquery-1.8.3.min.js';
document.getElementsByTagName('head')[0].appendChild(fm_j);
}
This is a timing issue. When you load scripts dynamically like that, they are loaded asynchronously and don't block further execution of javascript on the page. This means that jQuery may not be loaded by the time your jQuery specific code is being run.
When you refresh, js/jquery-1.8.3.min.js has probably been cached and so will load faster, so you don't see errors.
The solution is to wrap your javascript into a function that is called once jQuery has loaded using a load event handler. Here's an example I adapted from this tutorial.
working example.
function getScript(success) {
var fm_j = document.createElement('script');
fm_j.type = 'text/javascript';
fm_j.src = 'js/jquery-1.8.3.min.js',
done = false;
// Attach handlers for all browsers
fm_j.onload = fm_j.onreadystatechange = function () {
if (!done && (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete')) {
done = true;
// callback function provided as param
success();
};
};
document.getElementsByTagName('head')[0].appendChild(fm_j);
};
if(!window.jQuery) {
getScript(doSomething);
} else {
doSomething();
}
Also, as several commentors pointed out, many sites place banner ads inside iframes to keep the ads from "polluting" your page with their libraries.
iFrame could have been a better way to go #flyersun
It's simple and easy and effective, see here
http://support.microsoft.com/kb/272246

Script onreadystatechange race condition in Internet Explorer for multiple jQuery versions

imagine the following setup:
A page that has an old jQuery version (say 1.5.2) - that I have no control over - loads a Javascript file from my servers that also need jQuery, but a more recent version. (for example 1.8.3) Now my script tries to do the following:
var script = document.createElement("script");
script.setAttribute("type", "text/javascript");
script.setAttribute("src", "http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js");
script.onreadystatechange = function() { // IE
if (script.readyState === "complete" || script.readyState === "loaded") {
ready();
}
};
script.onload = function() { // other browsers
ready();
};
(document.getElementsByTagName("head")[0] || document.documentElement).appendChild(script);
The ready function then checks if $ has the correct version of jQuery and if it does, it binds that jQuery instance to another variable and returns $ to the original jQuery version, via newjQuery = window.jQuery.noConflict(true);.
Now this works all fine and dandy and there is no (outside) code execution happening between loading "my" jQuery version and restoring $ to "their" jQuery version - at least on Chrome, Firefox, etc. Where this approach fails is Internet Explorer, which for some reason processes at least 1 more "tick" of Javascript code that might be running in parallel. This tends to mess up code that is not compatible with "my" jQuery version and happens to get executed in the 5ms where IE has not executed the ready event yet.
Here's an example fiddle: http://jsfiddle.net/w5pPp/3/
In the fiddle, I test for the currently bound jQuery version every 10ms. Only in IE9 there sometimes is a short time span where $ refers to "my" jQuery, as indicated by a "THIS SHOULD NOT HAPPEN" log.
Now my question is this:
What would be the best solution to load "my" jQuery version into its own variable without causing any problems in the execution of the page code in the short time span where it overwrites "their" jQuery before calling noConflict?
When you load your version of jQuery, try the following:
<!-- load your jQuery version -->
<script type="text/javascript" src="http://example.com/jquery-1.9.1.js"></script>
<script type="text/javascript">
var $_mine = $.noConflict(true);
</script>
<!-- initialize their scripts -->
<script type="text/javascript" src="http://example.com/their-jquery.js"></script>
<script type="text/javascript" src="http://example.com/their-script.js"></script>
This should result in you having $_mine available to utilize your version of jQuery, without conflicting with the other script, and its use of $, which will refer to the outdated version.
As mentioned in commentary above, refer to Can I use multiple versions of jQuery on the same page? for further details / information / examples.
EDIT:
It sounds as if this won't resolve your issue, based on the comments above. In this case, my suspicion is that you are actually seeing an issue of asynchronicity of download speeds between your cdn's. Try loading both your AND their version of jQuery the same way, one after the other.
In other words:
function loadScript(variable_name, script_url) {
var script = document.createElement("script");
script.setAttribute("type", "text/javascript");
script.setAttribute("src", script_url);
script.onload = function() {
if (variable_name != undefined) {
window[variable_name] = jQuery.noConflict(true);
console.log("after attach: " + window[variable_name].fn.jquery);
}
};
(document.getElementsByTagName("head")[0] || document.documentElement).appendChild(script);
};
loadScript('newjQuery', 'http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js');
loadScript('$', 'http://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js');
//loadScript(undefined, 'http://example.com/some/dependent/script/requiring-1.5.2.js');
Here is a working jsFiddle which shows this method working: http://jsfiddle.net/w5pPp/5/
The trick is loading the two items sequentially, and loading the dependencies after the jQuery versions are in place.

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.

Scope or timing issue while loading jQuery and jQueryUI in bookmarklet via <script>?

Edit: Details updated to add differences in Firefox/Chrome behavior
I am trying to create a bookmarklet that will load both jQuery and jQueryUI. The jQuery load uses javascript, but I figured since jQuery was loaded I'd go ahead and use it for the UI loading. More than getting it to work I really want to understand why this doesn't work. I'm still wrapping my head around scope/closures/etc. But I just don't see why in firefox $ doesn't work but "jQuery" does! The $ works fine in Chrome but I get a DIFFERENT issue there.
Notes:
1) In FireBug/FireFox I get '$("head") is undefined'
2) In Chrome the "$" works fine, but the jQueryUI call fails with Object [object Object] has no method 'dialog'
3) the callback guarantees jQuery is loaded by the time I try to use it. In Firefox if I replace "$" with "jQuery" ( such as jQuery("head) ) then the code works!.
4) there are no other libraries on the page already using $
5) Even more frustrating, in Firefox if I just give in and use "jQuery" rather than "$" and then set the callback from $("#jquilib").load() to call a third function, jQueryUI functions such as .tabs() and .dialog() are unavailalble even though the callback itself was triggered by jQueryUI being available!
6) In Chrome the jQueryUI issue goes away if I use setTimeout() to 100ms. If I go down to 1ms or something than the issue persists.
I am using the getScript function from this post: http://www.learningjquery.com/2009/04/better-stronger-safer-jquerify-bookmarklet.
Below is my code:
function getScript(url,success){
var script=document.createElement('script');
script.src=url;
var head=document.getElementsByTagName('head')[0],
done=false;
// Attach handlers for all browsers
script.onload=script.onreadystatechange = function(){
if ( !done && (!this.readyState
|| this.readyState == 'loaded'
|| this.readyState == 'complete') ) {
done=true;
success();
script.onload = script.onreadystatechange = null;
head.removeChild(script);
}
};
head.appendChild(script);
}
function initializejQueryUI(){
if (typeof jQuery.ui == 'undefined'){
// jQueryUI library & jQueryUI cupertino theme
$('head').append("<link href='https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/themes/cupertino/jquery-ui.css' type='text/css' rel='stylesheet'>");
$('head').append("<script id='jquilib' type='text/javascript' src='https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js'></script>");
}
$("#jquilib").load($("<div>jQuery & UI Loaded!</div>").dialog());
}
getScript('https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.js', initializejQueryUI); // call initializejQueryUI as callback when jQuery loads
Ok, figured it out after a lot of trial an error. I went ahead and continued developing my script in Chrome seems it seemed I got further than in Firefox. When I completed my bookmarklet I tried it on a whim in Firefox and it worked there too! Here's what I learned:
1) The $("#jquilib").load($("<div>jQuery & UI Loaded!</div>").dialog()); call doesn't work because jQuery removes elements added via append from the DOM after processing the script! It was easier just to re-use the getScript() function to also get jQueryUI and put the alert in a function called from the callback. The tab creation issue I encountered (item #5 in the question above) was a result of this quirk.
Reference: http://api.jquery.com/append/ Search for Karl Swedberg saying "yes, it's normal"
2) Firebug seems to make use of the "$" while in the console, leading a situation like my description above where "$" doesn't work but jQuery() does work. There seem to be some rules governing when it releases the "$" because if i just try running the script again jQuery's $ shortcut suddenly works. This was the most frustrating part because it made it appear like a scope and/or timing issue!

Categories