This question already has answers here:
Why does jQuery or a DOM method such as getElementById not find the element?
(6 answers)
Closed 2 years ago.
First off I want to say I am quite new to JavaScript, but not entirely new to programming. I am familiar with python and just finished last semester at my college taking c++ and got an A. Now this semester I am taking JavaScript. I feel a bit silly asking this question because it seems quite stupid to me, but please be nice to me... Anyway, the very first part of my assignment is to write a function to count the hyperlinks on a webpage which the teacher provides. There should be 20. So, the teacher provides 2 lines of code to create an array of links and then console.log them. I copied and pasted them exactly as the teacher has them on the assignment page. The two lines are:
var myLinks = document.getElementsByTagName("a");
console.log("Links", myLinks.length);
Firstly, I typed these two lines directly into the console on chrome with the provided website open, the output is 20. Correct! So I happily copied and pasted the two lines into the linked JavaScript file and reload the page and it produces 0. I don't understand why... I hope this is not a silly question, but coming from c++ last semester, this really seems like a silly problem to me... Thank you for any help!
update: That was the whole JavaScript file. And I am only 3 weeks into the semester and still feel like this is all a bit over my head... Anyway, yes the script tag needed to be at the end of the body tag I guess. I did not realize it mattered... I apologize for the silly question... But thank you all, I appreciate the help.
<script>
function getAnchorLinkCount() {
var myLinks = document.getElementsByTagName("a");
console.log("Links", myLinks.length);
}
</script>
then
<body onload="getAnchorLinkCount()">
You suppose to get count when your DOM entirely loaded
Most likely, the function executed before the html was completely loaded. To avoid such problems, always wrap your JS in a ready handler. With JQuery, use:
$(document).ready(function(){
// your code here
});
For a pure JS equivalent, have a look at this thread.
The problem is, it's likely (we can't see all of your code) that the javascript is executing before DOM has finished loading.
Consider:
<script>
var myLinks = document.getElementsByTagName("a");
alert("Links" + myLinks.length);
</script>
<body>
foo
bar
</body>
Output: Links0
vs:
<body>
foo
bar
</body>
<script>
var myLinks = document.getElementsByTagName("a");
alert("Links" + myLinks.length);
</script>
Output: Links2
To avoid this issue there's a few suggestions:
Put javascript code after the <body> tag, not in the head.
Use something like jQuery's $(document).ready(...)
Put the javascript in the head, but call the onload method in the body tag <body onload = "myInitFunction()">
If you are dealing with DOM which is programming interface for HTML. You must wait for DOM structure to load so that it can be accessed in JavaScript
Use DOMContentLoaded, The DOMContentLoaded event is fired when the initial HTML document has been completely loaded and parsed.
Another solution could be including your script right before closing body tag which will be executed when all the DOM is loaded and parsed.
Try this:
document.addEventListener("DOMContentLoaded", function(event) {
var myLinks = document.getElementsByTagName("a");
console.log("Links", myLinks.length);
});
Note: As per the docs, A very different event - load - should be used only to detect a fully-loaded page. It is an incredibly popular mistake to use load where DOMContentLoaded would be much more appropriate, so be cautious.
There is no problem with the code that you have written but the problem can be when you are executing it.
First you need to wait until DOM is ready then you can call the js methods. That is why it is document.... which mean from the DOM tree get my element.
There can multiple ways to execute once DOM is ready
window.load
DOMContentLoaded
Put your script just before closing body tag. This ensure that your entire DOM is ready.
If your are using jquery you can use $(document).ready(function(){})
Below is a snippet where the all js codes are at the bottom of the page.
<body>
Link 1
Link 2
Link 3
Link 4
Link 5
Link 6
<script>
// Will give a Collection of a tags
var getListTagName = document.getElementsByTagName('a');
console.log('document.getElementsByTagName ',getListTagName.length);
// Does same but but document.querySelectorAll is preferred to match a css selector
var getListQuery = document.querySelectorAll('a');
console.log('document.querySelectorAll ',getList.length)
</script>
</body>
Hope this post will be helpful for you.
Related
HTML elements with a unique custom type attribute are ignored by the browser. Sometimes these are used by template engines. How do I define what happens when such a script element is loaded/created? (either while loading the page or when inserted dynamically)
In other words, does an onCreateElement event of some sorts exist in the DOM?
I could quite easily iterate through all script elements with attribute type=text/mycustomtype when the DOM loads using for instance the querySelector and then parse them with a function. This however does not work when a new script element is created and appended programatically. Is this currently possible?
var d = document.createElement('script')
d.setAttribute('type', 'text/mycustomtype')
d.innerHTML = 'define foo = 1;' // some code in some custom language
document.body.appendChild(d)
In this case, nothing will happen because the browser will ignore this unknown type. Can I somehow define a handler function for this? Thanks in advance.
I recently saw python script running in a browser using brython. View source and I see:
<script type="text/python3">
from interpreter import Interpreter
# open REPL in textarea with id "code"
Interpreter("code")
</script>
I wanted to know how this is possible. I googled for the answer, and found the dreaded stackoverflow question that's exactly what I want - with no answers.
I found a good answer in: Everything I Know About The Script Tag. It's exactly as you predicted when you say iterate through all script elements.
Their example looks like this:
<script type="text/emerald">
make a social network
but for cats
</script>
<script>
var codez = document.querySelectorAll('script[type="text/emerald"]');
for (var i=0; i < codez.length; i++)
runEmeraldCode(codez[i].innerHTML);
</script>
This question already has answers here:
How may I reference the script tag that loaded the currently-executing script?
(14 answers)
Closed 8 years ago.
I need to know if it is possible to obtain the current execution node?
Example:
..html
<script id="x">
console.log(document.currentNode.id); // << this must return "x"
</script>
..html
Thanks!
Modern browsers support a standard property on document object that points to the current script node:
https://developer.mozilla.org/en-US/docs/DOM/document.currentScript
<script id="x">
console.log(document.currentScript.id); // << this must return "x"
</script>
I don't know for 100% sure, but the collection of script tags returned by document.getElementsByTagName('script') should not include the script tags that are below the presently executing <script>. In other words, I think that this should work:
var arrScripts = document.getElementsByTagName('script');
var strScriptTagId = arrScripts[arrScripts.length - 1].id;
This will only work for scripts that are executing as the page loads. If this executes in a deferred script or as part of a page-load event, it will likely always report the last <script> in the completely rendered page. Note that the id tag is not a valid attribute for <script>, so your page won't likely validate. If you have any external scripts that write script tags (for example, third party ads), I think the code will be unpredictable. I played with this idea a couple years ago and the results were unsatisfactory.
Andrews Answer already has been a good idea but I experienced all the issues mentioned.
This is why I choosed a different approach which works well for IE,FF and Chrome.
Simply executing the script in an onload event of an image. Defining a transparent 1pixel gif inline and you will receive "this" when it fires.
This example is used to change DIV content dynamically while rendering. My target is to fill the div with a different innerHTML created by an browser based xsl rendering (not shown here).
For sure you even can load any image from the internet so it must not be inline. And the big benefit: the image and its event are replacing themself with the new content so even the image will disappear. The "div" even does not need any "id" assignment.
<div id="demo">
empty
<img onLoad="changeNodeOnTheFly(this,'hurra');void(0);" src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=="/>
</div>
The script:
<script>
function changeNodeOnTheFly(ele, text)
{
ele.parentNode.innerHTML=text;
}
</script>
BR
Heiko
Use document.write to find your position:
<script data-foo="bar">
var id = 'placeholder-' + Math.floor(Math.random() * 1e10)
document.write('<div id=' + id + '></div>')
var placeholder = document.getElementById(id)
var script = placeholder.previousSibling
placeholder.parentNode.removeChild(placeholder)
// "bar" is written to the document
document.write(script.getAttribute('data-foo'))
</script>
Why not use:
<script id="x">
console.log(document.getElementById("x").id);
</script>
can anyone explain what happens when you use javascript to insert a javascript based widget?
here's my js code:
var para = document.getElementsByTagName("p");
var cg = document.createElement("div");
cg.setAttribute("class", "twt");
cg.innerHTML='<a href="http://twitter.com/share" class="twitter-share-button"
data-count="vertical" data-via="xah_lee">Tweet</a>
<script type="text/javascript" src="http://platform.twitter.com/widgets.js"></script>';
document.body.insertBefore(cg, para[1]);
it inserts the twitter widget, before the first paragraph. As you can see above, the twitter widget calls for a javascript that shows how many time the page has been tweeted.
doesn't work in Firefox, Chrome, but semi-works in IE8. What should be the expected behavior when this happens? Does the newly inserted js code supposed to execute? If so, how's it differ from if the code is on the page itself?
In order to execute the JS code you insert into a DIV via innerHTML, you need to do something like the following (courtesy of Yuriy Fuksenko at http://www.coderanch.com/t/117983/HTML-JavaScript/Execute-JavaScript-function-present-HTML )
function setAndExecute(divId, innerHTML) {
var div = document.getElementById(divId);
div.innerHTML = innerHTML;
var x = div.getElementsByTagName("script");
for (var i=0;i<x.length;i++) {
eval(x[i].text);
}
}
A slightly more advanced approach is here: http://zeta-puppis.com/2006/03/07/javascript-script-execution-in-innerhtml-the-revenge/ - look for <script> tags, take their conĀtent and create a new eleĀment into the <head>.
innerHTML does not work to insert script tags (because the linked script, in most browsers, will fail to execute). Really, you should insert the script tag once on the server side and insert only the link at the location of each post (that is, if you are adding this to a blog home page that shows multiple posts, each with their own URLs).
If, for some reason, you decide that you must use one snippet of JavaScript to do it all, at least import the tweet button script in a way that will work, for example, the Google Analytics way or the MediaWiki way (look for the importScriptURI function). (Note that I do not know the specifics of the tweet button, so it might not even work.)
Is it possible to get in some way the original HTML source without the changes made by the processed Javascript? For example, if I do:
<div id="test">
<script type="text/javascript">document.write("hello");</script>
</div>
If I do:
alert(document.getElementById('test').innerHTML);
it shows:
<script type="text/javascript">document.write("hello");</script>hello
In simple terms, I would like the alert to show only:
<script type="text/javascript">document.write("hello");</script>
without the final hello (the result of the processed script).
I don't think there's a simple solution to just "grab original source" as it'll have to be something that's supplied by the browser. But, if you are only interested in doing this for a section of the page, then I have a workaround for you.
You can wrap the section of interest inside a "frozen" script:
<script id="frozen" type="text/x-frozen-html">
The type attribute I just made up, but it will force the browser to ignore everything inside it. You then add another script tag (proper javascript this time) immediately after this one - the "thawing" script. This thawing script will get the frozen script by ID, grab the text inside it, and do a document.write to add the actual contents to the page. Whenever you need the original source, it's still captured as text inside the frozen script.
And there you have it. The downside is that I wouldn't use this for the whole page... (SEO, syntax highlighting, performance...) but it's quite acceptable if you have a special requirement on part of a page.
Edit: Here is some sample code. Also, as #FlashXSFX correctly pointed out, any script tags within the frozen script will need to be escaped. So in this simple example, I'll make up a <x-script> tag for this purpose.
<script id="frozen" type="text/x-frozen-html">
<div id="test">
<x-script type="text/javascript">document.write("hello");</x-script>
</div>
</script>
<script type="text/javascript">
// Grab contents of frozen script and replace `x-script` with `script`
function getSource() {
return document.getElementById("frozen")
.innerHTML.replace(/x-script/gi, "script");
}
// Write it to the document so it actually executes
document.write(getSource());
</script>
Now whenever you need the source:
alert(getSource());
See the demo: http://jsbin.com/uyica3/edit
A simple way is to fetch it form the server again. It will be in the cache most probably. Here is my solution using jQuery.get(). It takes the original uri of the page and loads the data with an ajax call:
$.get(document.location.href, function(data,status,jq) {console.log(data);})
This will print the original code without any javascript. It does not do any error handling!
If don't want to use jQuery to fetch the source, consult the answer to this question: How to make an ajax call without jquery?
Could you send an Ajax request to the same page you're currently on and use the result as your original HTML? This is foolproof given the right conditions, since you are literally getting the original HTML document. However, this won't work if the page changes on every request (with dynamic content), or if, for whatever reason, you cannot make a request to that specific page.
Brute force approach
var orig = document.getElementById("test").innerHTML;
alert(orig.replace(/<\/script>[.\n\r]*.*/i,"</script>"));
EDIT:
This could be better
var orig = document.getElementById("test").innerHTML + "<<>>";
alert(orig.replace( /<\/script>[^(<<>>)]+<<>>/i, "<\/script>"));
If you override document.write to add some identifiers at the beginning and end of everything written to the document by the script, you will be able to remove those writes with a regular expression.
Here's what I came up with:
<script type="text/javascript" language="javascript">
var docWrite = document.write;
document.write = myDocWrite;
function myDocWrite(wrt) {
docWrite.apply(document, ['<!--docwrite-->' + wrt + '<!--/docwrite-->']);
}
</script>
Added your example somewhere in the page after the initial script:
<div id="test">
<script type="text/javascript"> document.write("hello");</script>
</div>
Then I used this to alert what was inside:
var regEx = /<!--docwrite-->(.*?)<!--\/docwrite-->/gm;
alert(document.getElementById('test').innerHTML.replace(regEx, ''));
If you want the pristine document, you'll need to fetch it again. There's no way around that. If it weren't for the document.write() (or similar code that would run during the load process) you could load the original document's innerHTML into memory on load/domready, before you modify it.
I can't think of a solution that would work the way you're asking. The only code that Javascript has access to is via the DOM, which only contains the result after the page has been processed.
The closest I can think of to achieve what you want is to use Ajax to download a fresh copy of the raw HTML for your page into a Javascript string, at which point since it's a string you can do whatever you like with it, including displaying it in an alert box.
A tricky way is using <style> tag for template. So that you do not need rename x-script any more.
console.log(document.getElementById('test').innerHTML);
<style id="test" type="text/html+template">
<script type="text/javascript">document.write("hello");</script>
</style>
But I do not like this ugly solution.
I think you want to traverse the DOM nodes:
var childNodes = document.getElementById('test').childNodes, i, output = [];
for (i = 0; i < childNodes.length; i++)
if (childNodes[i].nodeName == "SCRIPT")
output.push(childNodes[i].innerHTML);
return output.join('');
This question already has answers here:
How may I reference the script tag that loaded the currently-executing script?
(14 answers)
Closed 8 years ago.
I need to know if it is possible to obtain the current execution node?
Example:
..html
<script id="x">
console.log(document.currentNode.id); // << this must return "x"
</script>
..html
Thanks!
Modern browsers support a standard property on document object that points to the current script node:
https://developer.mozilla.org/en-US/docs/DOM/document.currentScript
<script id="x">
console.log(document.currentScript.id); // << this must return "x"
</script>
I don't know for 100% sure, but the collection of script tags returned by document.getElementsByTagName('script') should not include the script tags that are below the presently executing <script>. In other words, I think that this should work:
var arrScripts = document.getElementsByTagName('script');
var strScriptTagId = arrScripts[arrScripts.length - 1].id;
This will only work for scripts that are executing as the page loads. If this executes in a deferred script or as part of a page-load event, it will likely always report the last <script> in the completely rendered page. Note that the id tag is not a valid attribute for <script>, so your page won't likely validate. If you have any external scripts that write script tags (for example, third party ads), I think the code will be unpredictable. I played with this idea a couple years ago and the results were unsatisfactory.
Andrews Answer already has been a good idea but I experienced all the issues mentioned.
This is why I choosed a different approach which works well for IE,FF and Chrome.
Simply executing the script in an onload event of an image. Defining a transparent 1pixel gif inline and you will receive "this" when it fires.
This example is used to change DIV content dynamically while rendering. My target is to fill the div with a different innerHTML created by an browser based xsl rendering (not shown here).
For sure you even can load any image from the internet so it must not be inline. And the big benefit: the image and its event are replacing themself with the new content so even the image will disappear. The "div" even does not need any "id" assignment.
<div id="demo">
empty
<img onLoad="changeNodeOnTheFly(this,'hurra');void(0);" src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=="/>
</div>
The script:
<script>
function changeNodeOnTheFly(ele, text)
{
ele.parentNode.innerHTML=text;
}
</script>
BR
Heiko
Use document.write to find your position:
<script data-foo="bar">
var id = 'placeholder-' + Math.floor(Math.random() * 1e10)
document.write('<div id=' + id + '></div>')
var placeholder = document.getElementById(id)
var script = placeholder.previousSibling
placeholder.parentNode.removeChild(placeholder)
// "bar" is written to the document
document.write(script.getAttribute('data-foo'))
</script>
Why not use:
<script id="x">
console.log(document.getElementById("x").id);
</script>