The code below, produces the same annoying error. It will return the button element in the first pass of the loop but it only returns null thereafter. Any ideas?
<script>
function Check_Submission()
{var Entry = [];
for(var i = 0; i < 14; i++)
{
for(var j = 0; j < 10; j++)
{
Entry[i] = document.getElementById('Add');
document.write(Entry + '<br>');
}
}
}
</script>
<button id = 'Add' onclick = "Check_Submission()" >Click me.</button>
You can not use document.write after the page load. When you do that it wipes away the page content.
First loop it finds the element
You write to the page, it removes the button
other iterations can not find it since it was removed.
You need to use DOM methods to add new content or use the console for debugging.
When you do document.write() to an already loaded document, it clears the current document and starts writing a new empty document.
So, as soon as you call the first document.write() in your loop, it clears the current document and then document.getElementById('Add') will no longer find the former content.
Probably what you should do is to use DOM insertion methods such as .appendChild() or .insertBefore() to add new content to an existing loaded page.
It seems to me like the first time you run your for loop, you use document.write. That will clear everything, so the document.getElementById('Add') will return nothing. what you really want to do is something like 'appendChild' or modifying the innerHTML of the element.
document.write will clear everything each time it is executed.
Try writing,
document.getElementById('divid').innerHTML+=Entry+'<br>';
<div id='divid'></div>
Related
When I run this script, the page is continuously loading and eventually freezes. Is this because everytime I create an element, the main DOMContentLoaded listener is being called?
If so, how can I stop this recursive behaviour and just add one node to every pre existing node?
//Waits for page to load
document.addEventListener('DOMContentLoaded', function() {
//Get all elements
var items = document.getElementsByTagName("*");
//Loop through entire DOM
for (var i = 0; i < items.length; i++) {
//If it is not a text node
if (!(items[i].nodeType == 3)){
//Create a div
var newDiv = document.createElement("div");
//Add div to current object
items[i].appendChild(newDiv);
}
}
});
It's because items is referencing a "live list". This means that any updates to the DOM are going to be reflected in your list if they match the original selector.
Because you're appending a div, and your selector selects all elements, it gets added to the list, pushing any subsequent members up an index, and so the iteration continues.
To avoid this, make a non-live copy of the collection before iterating.
var items = Array.from(document.getElementsByTagName("*"));
And FYI, the if (!(items[i].nodeType == 3)){ can be removed because getElementsByTagName will never return text nodes.
If you're supporting very old versions of IE, you may want to check that the .nodeType === 1, since some of those old versions included comment nodes when using "*".
Lastly, you can use modern features to clean this up a bit.
document.addEventListener('DOMContentLoaded', () => {
for (const el of [...document.getElementsByTagName("*")]) {
var newDiv = el.appendChild(document.createElement("div"));
// Work with newDiv
}
});
You get a continuously loading page because you have this:
var items = document.getElementsByTagName("*");
Which returns a "live" node list - meaning a list that can/will change as the matched elements change. Since your selector is for everything and then you create new elements, the set of matched elements changes (it gets bigger). Which, in turn causes the length of the node list to change, which keeps your loop running.
You should not try to match all the elements or you should use another method for getting the elements that doesn't return a live node list, like querySelectoAll()
I want to get all the <a> tags from an Html page with this JavaScript method:
function() {
var links = document.getElementsByTagName('a');
var i=0;
for (var link in links){i++;}
return i;
}
And i noticed it's won't return the correct number of a tags.
Any idea what can by the problem?
Any idea if there is any other way to get all the href in an Html ?
Edit
I tried this method on this html : http://mp3skull.com/mp3/nirvana.html .
And i get this result:"1". but there are more results in the page.
You don't need a loop here. You can read length property.
function getACount() {
return document.getElementsByTagName('a').length;
}
You don't have to loop over all of them just to count them. HTMLCollections (the type of Object that is returned by getElementsByTagName has a .length property:
$countAnchors = function () {
return document.getElementsByTagName('a').length;
}
Using getElementsByTagName("a") will return all anchor tags, not only the anchor tags that are links. An anchor tags needs a value for the href property to be a link.
You might be better off with the links property, that returns the links in the page:
var linkCount = document.links.length;
Note that this also includes area tags that has a href attribute, but I assume that you don't have any of those.
UPDATE Also gets href
You could do this
var linkCount = document.body.querySelectorAll('a').length,
hrefs= document.body.querySelectorAll('a[href]');
EDIT See the comment below, thanks to ttepasse
I would cast them to an array which you then slice up, etc.
var array = [];
var links = document.getElementsByTagName("a");
for(var i=0; i<links.length; i++) {
array.push(links[i].href);
}
var hrefs = array.length;
The JavaScript code in the question works as such or, rather, could be used to create a working solution (it’s now just an anonymous function declaration). It could be replaced by simpler code that just uses document.getElementsByTagName('a').length as others have remarked.
The problem however is how you use it: where it is placed, and when it is executed. If you run the code at a point where only one a element has been parsed, the result is 1. It needs to be executed when all a elements have been parsed. A simple way to ensure this is to put the code at the end of the document body. I tested by taking a local copy of the page mentioned and added the following right before the other script elements at the end of document body:
<script>
var f = function() {
var links = document.getElementsByTagName('a');
var i=0;
for (var link in links){i++;}
return i;
};
alert('a elements: ' + f());
</script>
The results are not consistent, even on repeated load of the page on the same browser, but this is probably caused by some dynamics on the page, making the number of a elements actually vary.
What you forget here was the length property. I think that code would be:
var count = 0;
for (var i = 0; i < links.length; i++) {
count++;
}
return count;
Or it would be:
for each (var link in links) {
i++;
}
length is used to determine or count the total number of the element which are the result.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for (For Loop)
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for_each...in (Foreach Loop)
I have the folowing code:
var transitionsSettingsClass = document.getElementsByClassName("transitionsSettings");
var transitionsSettingsClassLenght = transitionsSettingsClass.length;
for (i=0; i < transitionsSettingsClassLenght; i++);
{
transitionsSettingsClass[i].setAttribute("data-transition",transitionsSettings);
};
I know that transitionsSettingsClassLenght = 6 because I have checked it with alert. But when I put an alert inside cycle then it shows only 1-time (it should show 6-times). An also attribute data-transition is not set. But when I replace "i" inside transitionsSettingsClass[i] with transitionsSettingsClass[0] my first element changes and it is working. This script is supposed to change attribute data-transition in 6 elements.
Remove the ; at the end of
for (i=0; i < transitionsSettingsClassLenght; i++);
The for here only commands the code before the ;, that is nothing.
I'd recommend you to use the most frequent javascript style, as explicited by Google, as it helps avoid this kind of errors.
Have you tried with jquery each method?
$('.transitionsSettings').each(function(index) {
$(this).setAttribute("data-transition",transitionsSettings);
});
Just as a sidenote:
In all modern browsers you can set data- attributes by calling
node.dataset.transition = transitionsSettings;
The code below is interpreted as follows:
for (i=0; i < transitionsSettingsClassLenght; i++);
{
transitionsSettingsClass[i].setAttribute("data-transition",transitionsSettings);
};
The first line: for (i=0; i < transitionsSettingsClassLenght; i++); is executed 6 times as Javascript thinks its a single statement. Then it encounters
{
transitionsSettingsClass[i].setAttribute("data-transition",transitionsSettings);
}; which is executed once as a block. Removing the ; from the end of the for loop will solve the problem.
I'm trying to parse a page with javascript to replace links belonging to a specific class with an iframe to open a corresponding wikipedia page [so that rather than having a link you have an embedded result]. The function detects links properly but something about the replaceChild() action causes it to skip the next instance... as if it does the first replace and then thinks the next link is the one it just worked on, probably as a result of the loop.
For example, if there's 2 links on the page, the first will parse and the second will not even be seen but if there's 3, the first two will be parsed using the attributes from the first and third.
Can anyone suggest an alternative way of looping through the links that doesn't rely on a count function? Perhaps adding them to an array?
Sample Links
wiki it
Sample Javascript
(function(){
var lnks = document.getElementsByTagName("a");
for (var i = 0; i < lnks.length; i++) {
lnk = lnks[i]; if(lnk.className == "myspeciallinks"){
newif=document.createElement("iframe");
newif.setAttribute("src",'http://www.wikipedia.com');
newif.style.width="500px";
newif.style.height="100px";
newif.style.border="none";
newif.setAttribute("allowtransparency","true");
lnk.parentNode.replaceChild(newif,lnk);
}
}
})();
The problem here is that document.getElementsByTagName returns a NodeList and not an array. A NodeList is still connected to the actual DOM, you cannot safely iterate over its entries and at the same time remove the entries from the DOM (as you do when you replace the links).
You will need to convert the NodeList into an array and use the array for iteration:
(function(){
var lnksNodeList = document.getElementsByTagName("a");
// create an array from the above NodeList and use for iteration:
var lnks = Array.prototype.slice.call(lnksNodeList);
for (var i = 0; i < lnks.length; i++) {
var lnk = lnks[i];
if (lnk.className == "myspeciallinks") {
var newif = document.createElement("iframe");
newif.setAttribute("src", 'http://www.wikipedia.com');
newif.style.width = "500px";
newif.style.height = "100px";
newif.style.border = "none";
newif.setAttribute("allowtransparency", "true");
lnk.parentNode.replaceChild(newif, lnk);
}
}
})();
According to the MDN documentation:
Returns a list of elements with the given tag name. The subtree underneath the specified element is searched, excluding the element itself. The returned list is live, meaning that it updates itself with the DOM tree automatically. Consequently, there is no need to call several times element.getElementsByTagName with the same element and arguments.
Therefore, the collection shrinks every time you replace an a. You could change your loop to decrement i whenever you do a replace.
Well im new to javascript but why does this not work, all i want to do is to get a list of all selects on the page.
var elements = document.getElementsByTagName("select");
alert("there are " + elements.length + " select's");
for (i = 0; i < elements.length; i++)
{
alert(elements[i].getAttribute('Id'));
}
Edit: the error is that it does not find any selects at all, elements.length is allways zero!
You'r saying that elements.length is always returning 0 for you, this could be because:
You are running the JS code in the beginning of your page, thus the DOM is not fully available yet
Try using .id instead of of getAttribute('Id').
I guess the part of getting id attribute doesn't work for you. Probably it's because you typed there "Id" instead of "id".
The usual cause for getElementsByTagName returning zero results in a document with matching elements is that it is being run before the elements appear in the document (usually in the section and not inside a function that is called onload or onDomReady).
Move the element to just before the (END of body!) tag, or use an event handler that fires after the HTML has all been processed.
Well, as far as I can see is that perhaps the selects on your page don't have Id's (the alerts in the loop show null)