I am in the middle of creating a small script to 'help' me with my homework. It uses jQuery. The script (so far) is below:
var s = document.createElement('script');
document.body.appendChild(s);
s.src = "http://code.jquery.com/jquery-latest.js"; // Include jQuery
var tmp_1 = document.embeds[0].GetVariable("q1answers"); // Read raw values
var answers_1 = tmp_1.split(","); // Explode into array
answers_1.splice(0,1); // Remove first element (always 0)
var tmp_2 = document.embeds[0].GetVariable("q2answers");
var answers_2 = tmp_2.split(",");
answers_2.splice(0,1);
answers_1.push("LINE_BREAK");
var answers = answers_1.concat(answers_2);
$("body").append("<div id='answers-wrap'></div>");
$("#answers-wrap").css("position", "fixed");
$("#answers-wrap").css("background", "none");
The problem arises when it gets to the 3rd-to-last line. Chrome console claims that Object #<HTMLBodyElement> has no method 'append', however if I extract that line and put it into the console on its own, it works fine. I can use a different method to insert HTML, but I would like to know what isn't working with this one.
Thanks in advance!
Since you're adding the jQuery script dynamically, it's loaded asynchronously, so it's probably not loaded yet when you're trying to use it. Use an onload handler for the dynamic script block:
var s = document.createElement('script');
document.body.appendChild(s);
s.src = "http://code.jquery.com/jquery-latest.js"; // Include jQuery
s.onload = function() {
$("body").append("<div id='answers-wrap'></div>");
$("#answers-wrap").css("position", "fixed");
$("#answers-wrap").css("background", "none");
}
The error message you're getting also indicates that $ exists (another library, maybe?) and is not returning a jQuery object, so you'll probably have to use jQuery in "noConflit" mode, and use jQuery or a user-defined alias instead of $.
Just a guess, but may you are running the script before the browser has finished rendering the DOM?
Try wrapping the code in
window.onload = function(){
// ... your code here
};
in order to execute it onload.
EDIT: changed code to reflect the feedback below, of course one cannot use jQuery's $ before jQuery is loaded, my fault.
Related
This question asks for a way to open a new window using window.open and then inject it with a script. It was not possible because of cross-domain security issues.
However, my problem is that I want to do the exact same thing, except from the same domain to the same domain. Is this possible?
Note that .write does not solve this problem because it wipes all the html from the page first.
You can do something like this:
var theWindow = window.open('http://stackoverflow.com'),
theDoc = theWindow.document,
theScript = document.createElement('script');
function injectThis() {
// The code you want to inject goes here
alert(document.body.innerHTML);
}
theScript.innerHTML = 'window.onload = ' + injectThis.toString() + ';';
theDoc.body.appendChild(theScript);
This also seems to work:
var theWindow = window.open('http://stackoverflow.com'),
theScript = document.createElement('script');
function injectThis() {
// The code you want to inject goes here
alert(document.body.innerHTML);
}
// Self executing function
theScript.innerHTML = '(' + injectThis.toString() + '());';
theWindow.onload = function () {
// Append the script to the new window's body.
// Only seems to work with `this`
this.document.body.appendChild(theScript);
};
And if for some reason you want to use eval:
var theWindow = window.open('http://stackoverflow.com'),
theScript;
function injectThis() {
// The code you want to inject goes here
alert(document.body.innerHTML);
}
// Self executing function
theScript = '(' + injectThis.toString() + '());';
theWindow.onload = function () {
this.eval(theScript);
};
What this does (Explanation for the first bit of code. All examples are quite similar):
Opens the new window
Gets a reference to the new window's document
Creates a script element
Places all the code you want to 'inject' into a function
Changes the script's innerHTML to load said function when the window
loads, with the window.onload event (you can also use addEventListener). I used toString() for convenience, so you don't have to concatenate a bunch of strings. toString basically returns the whole injectThis function as a string.
Appends the script to the new window's document.body, it won't actually append it to the document that is loaded, it appends it before it loads (to an empty body), and that's why you have to use window.onload, so that your script can manipulate the new document.
It's probably a good idea to use window.addEventListener('load', injectThis.toString()); instead of window.onload, in case you already have a script within your new page that uses the window.onload event (it'd overwrite the injection script).
Note that you can do anything inside of the injectThis function: append DIVs, do DOM queries, add even more scripts, etc...
Also note that you can manipulate the new window's DOM inside of the theWindow.onload event, using this.
Yes...
var w = window.open(<your local url>);
w.document.write('<html><head>...</head><body>...</body></html>');
Here's a trick I use, it uses query strings, and is client side. Not perfect but it works:
On the sending page, do:
var javascriptToSend = encodeURIComponent("alert('Hi!');");
window.open('mypage.html?javascript=' + javascriptToSend);
Replace mypage.html with your page. Now on the receiving page, add:
(location.href.match(/(?:javascript)=([^&]+)/)[1])&&eval(decodeURIComponent(location.href.match(/(?:javascript)=([^&]+)/)[1]));
You'll have to do some back-and forth to make sure this works.
If you HAVE PHP you can use this more reliable solution on the receiving page:
eval(decodeURIComponent(<?=$_GET['javascript'] ?>));
I'd like to load this code (1) via XMLHttpRequest in another page
<input type="text" onkeypress="info(event)"/>
<script>
function info(e) { console.log(e.keyCode); }
</script>
This (2) is the way I tried...
<div id="x"></div>
<script>
var xhr = new XMLHttpRequest();
xhr.onload = handleResponse.bind(xhr);
xhr.open("POST","test.php",true);
xhr.send();
function handleResponse() {
var x = document.getElementById("x");
x.innerHTML = this.responseText;
var js = x.getElementsByTagName("script")[0];
eval(js.innerText);
}
</script>
...and this is the error I got on keypress:
Uncaught ReferenceError: info is not defined
Why the info() is not found since its definition was eval'd? How to make the info fire on keypress if (2) should be unaware of (1)? No jQuery.
Following Mike's recommendation, I created this question to solve separated problem that leads to explanation of this problem.
(edited for es202020, because JS has changed drastically since 2013 and the old answer is now an anti-pattern. Don't use eval)
Scope. You didn't eval it on window, you added it to the scope of that function handleResponse so it won't exist outside of handleResponse. Also, in this case you don't really need eval at all, just create a script element and add that:
function handleResponse(evt) {
const s = document.createElement(`script`);
s.textContent = evt.responseText;
document.head.appendChild(s);
}
The browser already knows how to interpret scripts, but you need to add elements to the head if you want them to execute instead of be inserted as inactive DOM nodes after the page has already loaded.
Don't use eval().
Is there any way to check if javascript file is already attached to the page by its file name.
For eg :
if ("path-to-script/scriptname.js") already embeded
{
call related function
}
else
{
Append '<script src="path-to-script/scriptname.js" type="text/javascript"> </script> '
call related function
}
Basically I dont want 1 script to be attached twice on the same page.
You might not always know what objects or functions a script contains in advance, in such cases you can search for script tags containing the desired src.
With jquery:
$("script[src*='"+scriptName+"']");
Without jquery:
document.querySelector("script[src*='"+scriptName+"']");
You'd need to test whether the actual function from the script file exists, like this:
if (window.function_name) {
// script loaded
} else {
// script not loaded
}
I agree with #zathrus though I think you should be using requirejs for things like this. The idea is that dependencies must be fetched before executing the code. The above method you are using may work but you can not guarantee anything.
RequireJS will beautifully maintain all the dependency loading. It is very easy to learn as well.
Simply check if the library is defined, otherwise import it:
if ( !jQuery ) {
var s = document.createElement('script');
s.type = 'text/javascript';
document.body.appendChild(s);
s.src = "path-to-script/scriptname.js";
void(0);
}
// call function
you really need a script loader.. because as you said you want it specific with the javascript resource filename and this is sort of your javascript files are depending to each other
www.headjs.com
www.modernizr.com
www.yepnopejs.com
I thought this will help you.
if (typeof scriptname== "undefined") {
var e = document.createElement("script");
e.src = "scriptname.js";
e.type = "text/javascript";
document.getElementsByTagName("head")[0].appendChild(e);
}
I'm using a fairly simple system to load javascript dynamically:
include = function (url) {
var e = document.createElement("script");
e.src = url;
e.type="text/javascript";
document.getElementsByTagName("head")[0].appendChild(e);
};
Let's say I have a file test.js which has the following contents:
var foo = 4;
Now, in my original script, I want to use
include(test.js);
console.log(foo);
However, I get a 'foo has not been defined' error on this. I'm guessing it has to do with the dynamic script being included as the last child of the <head> tag. How can I get this to work?
It is because you have to wait for the script to load. It is not synchronous like you would think. This may work for you:
include = function (url, fn) {
var e = document.createElement("script");
e.onload = fn;
e.src = url;
e.async=true;
document.getElementsByTagName("head")[0].appendChild(e);
};
include("test.js",function(){
console.log(foo);
});
That is one problem, but it also takes time for the browser to download and parse the remote JS file — and it hasn't done that before you call console.log.
You need to delay things until the script has loaded.
This is easiest done by letting a library do the heavy lifting, jQuery has a getScript method that lets you pass a callback to run when the script has loaded.
I am trying to build some sort of logger functionality in javascript. Is there any API for a script to get its own filename?
This should work:
(new Error).fileName
Or you can try this:
var filepath;
(function(){
var scripts = document.getElementsByTagName('script');
filepath = scripts[ scripts.length-1 ].src;
}());
The second option gives you the path of your script file.
I see two ways:
put into every JS file a variable var filename = 'script.js';
get the filename using <script> tag name
JS can not get filename like bash/perl/c scripts.
If we can get the current script's tag, then we can read its src attribute. Excerpt from https://stackoverflow.com/a/22745553/4396817 below:
document.currentScript will return the element whose script is currently being processed.
<script>
var me = document.currentScript;
</script>
Benefits
Simple and explicit. Reliable.
Don't need to modify the script tag
Works with asynchronous scripts (defer & async)
Works with scripts inserted dynamically
Problems
Will not work in older browsers and IE.
...So from there, we can simply read the src attribute!
<script src="http://website.com/js/script.js">
alert(document.currentScript.src);
</script>
// Alerts "http://website.com/js/script.js"
Unfortunately this is not possible.
If you change your approach, getting function names may help you which is sometimes possible. Your best chance would be extracting function name from "arguments.callee". This only works if function is defined like
function FN() { ... }
And does not work when
var FN = function() { ... }
this is my modification that fixes a few possible issues, but adds a requirement.
It needs you to name the file in a certain way, so for example if you have a .js file, but you want to know which version is loaded (for example to tell a php server). so your js file would be "zoom_v34.js".
var version;
(function(){
var scripts = document.getElementsByTagName('script');
for (var i=0; i<scripts.length; i++) {
var start = scripts[i].src.indexOf('zoom_');
if (start != -1) { var end = scripts[i].src.indexOf('.',start); version = scripts[i].src.substr(start+6,end-start-6); break; }
}
}());
post='login{JS:'+version+'}';
You can try putting this at the top of your JavaScript file:
window.myJSFilename = "";
window.onerror = function(message, url, line) {
if (window.myJSFilename != "") return;
window.myJSFilename = url;
}
throw 1;
Make sure you have only functions below this. The myJSFilename global variable will contain the full path of the JavaScript file, and the filename can be parsed from that. Tested in IE11, but it should work elsewhere.