Why is element.tagName undefined? - javascript

I was having a little play around this morning and I thought it would be fun to do something silly and try and write all the tagnames of a page on that page using something like this
var elements = document.getElementsByTagName("*");
for(var element in elements) {
document.write(element.tagName + "<br />");
}
However all that gets written is undefined. Why is this? Oh and I'm using Firefox.

for...in is not guaranteed to work for a NodeList (which is what document.getElementsByTagName() returns), and even when it does, what you'll be getting as the value of element will be not be a reference to the element but rather a property name, such as the numeric index of the element in the NodeList. Use a normal for loop instead.
var elements = document.getElementsByTagName("*");
for (var i = 0; i < elements.length; ++i) {
document.write(elements[i].tagName + "<br />");
}
Also, document.write() won't work as you might expect after the document has loaded, which is when you'd typically use document.getElementsByTagName(). A better mechanism would be to populate an element in the page:
<div id="debug"></div>
Script:
var elements = document.getElementsByTagName("*");
var debugDiv = document.getElementById("debug");
var tagNames = [];
for (var i = 0; i < elements.length; ++i) {
tagNames.push(elements[i].tagName);
}
debugDiv.innerHTML = tagNames.join("<br>");

Because you're using a for...in loop, element is actually the item's key and not the value. elements[element] would give you the correct result, but you should use a proper for loop instead:
for (var i = 0; i < elements.length; i++) {
document.write(elements[i].tagName + "<br />");
}
This is because for...in may iterate over other enumerable properties that are not elements of the collection. These properties can differ between browsers.

You could try:
var elements = document.getElementsByTagName("*");
for (int i = 0; i < elements.length; i++)
{
document.write(elements.item(i).tagName + "<br />");
}

I suppose that is impossible, and is possible with jQuery/Sizzle HTML/CSS Selector:
$('*');
With that function/method you can only select "all available HTML tags" in your current document.
For example:
document.getElementByTagName('html');
document.getElementByTagName('head');
document.getElementByTagName('body');
document.getElementByTagName('h3');
document.getElementByTagName('p');
document.getElementByTagName('pre');
document.getElementByTagName('code');
document.getElementByTagName('metaforce'); // being a custom HTML(5) tag

Related

Using Native JavaScript, change the title attribute of an object if it has a certain CSS class

So by using native javascript, how would I go about saying
"if this object has this css class, add this to the title attribute"
document.addEventListener("DOMContentLoaded", function(event) {
if(element.classlist.contains("current_page_item")||element.classlist.contains("current-page-ancestor")){
}
});
That is as far as I've gotten, I'm trying to stick to native javascript just so we don't have to load up any libraries and can keep the site as minimalist as possible.
You can use getElementsByClassName()
var x = document.getElementsByClassName("current_page_item");
Then loop and add title
x.forEach(function(element){
element.title = "title";
});
or
for (var i = 0; i < x.length; i++) {
x[i].title ="title";
}
To answer to your comment, to apply the title to the "a" element that is a child of the div element that has the "current_page_item" class
for (var i = 0; i < x.length; i++) {
var y = x[i].getElementsByTagName("a");
y[0].title = "title";
}
Similar to Rohit Shetty's reply, you could also use the querySelector:
let elements = document.querySelector(".current_page_item");
elements.forEach(function(e) {
e.title = "title";
);
You can use getElementsByClassName()
var x = document.getElementsByClassName("current_page_item");
for(var i=0;i<x.length;i++){
x[i].title += "BLAH";
}
I don't now if I have understood well.
But let's try.
First, locate the elements.
const nodes = document.querySelectorAll('.current_page_item, .current_page_item')
// nodes are the elements of one of the classes names
Then, apply the class Names to title.
function containsOfTheClasses (node) {
return classNames.some(x => node.classList.contains(x))
}
nodes.forEach(function (node) {
node.title += classNames.filter(containsOfTheClasses).join(' ')
})

document.getElementsByTagName not working

I would like to use document.getElementsByTagName('input')
to set as required (or unset it) for a list of inputs.
is it possible?
I've tried:
document.getElementsByTagName('input').required = false;
or (for a different purpose)
document.getElementsByTagName('input').value = ""
but it doesn't seem work.
Moreover: is it possible to catch a certain type of input (i.e. text or radio)?
Thank you!!!
ObOnKen
getElementsByTagName() returns a collection of elements so you need to iterate over the collection...
var elements = document.getElementsByTagName('input');
for(var i = 0; i < elements.length; i++)
{
if(elements[i].type == "text")
{
elements[i].value = "";
}
}
getElementsByTagName() returns a live HTMLCollection. If you want to do something to each item returned, you'll have to explicitly iterate across them:
var inputs = table.getElementsByTagName('input');
for (var i = 0; i < inputs.length; i++) {
inputs[i].required = false;
}
However, if you use some libraries, you may be able to operate on each of the contents of a collection (or, as some of the libraries call them, selection) en-masse with a syntax as you seem to expect.
You should use for loop for iterating all inputs, because document.getElementsByTagName returns a HTMLCollection of elements with the given tag name.
var values = document.getElementsByTagName('input');
for (var i = 0; i < values.length; i++) {
values[i].required = false;
}
To catch a certain type of input:
var textInput = document.querySelector("input[type=text]");
querySelector returns the first element within the document.

JavaScript use for loop to create p tag with innerHTML content filled in

i am using a for loop to generate paragraph tags based on the length of my array. I want each of these p tags generated to have the same innerHTML. I can get the tags to generate with the class name but the innerHTML remains blank.
I have tried the following to no avail, not sure what I am doing wrong.
for (i = 0; i < numArray.length; i++) {
var line = document.createElement("p");
line.className = "line";
document.body.appendChild(line);
var b = document.getElementsByClassName("line");
b.innerHTML = "|";
}
You don't need to call getElementsByClassName you can change the innerHTML of line since you already have the reference to the DOM element.
for (i = 0; i < numArray.length; i++) {
var line = document.createElement("p");
line.className = "line";
line.innerHTML = "|";
document.body.appendChild(line);
}
And explaining why it didn't work, it's because getElementsByClassName returns a collecion of elements, you need to loop through them.
getElementsByClassName should return an array of elements, not a single element. You could try: getElementsByClassName('line')[i], if there is some reason you are doing that specifically.
Note: getElementsByClassName('line')[i] may not refer to the object you just created, unless there are no other "line"s on the page. It scans the document for all elements that have a class called line, which could be paragraphs or other element types.
For a better alternative, please refer to changes made below. This:
caches the numArray length into a variable, so you are not performing that operation at each loop iteration
sets the HTML and ClassName of the element you created before attaching it to the document; which has a number of performance benefits
does not unnecessarily do a DOM lookup for elements, which is expensive
uses the var keyword to avoid scoping conflicts for loop variables
JS Fiddle:
for ( var i=0, n=numArray.length; i < n; i++) {
var line = document.createElement("p");
line.className = "line";
line.innerHTML = '|';
document.body.appendChild(line);
}

getElementsByClassName produces error "undefined" [duplicate]

This question already has answers here:
What do querySelectorAll and getElementsBy* methods return?
(12 answers)
Closed 8 years ago.
I have several textboxes with the class output. I would like to be able to print their values as a plain HTML list in a div with ID combined. Right now, I have the following code:
function doCombine() {
document.getElementById('combined').innerHTML =
document.getElementsByClassName('output').value + ",";
}
Yet, when I run the function, i get the error message undefined,. When i add a [0] before .value, it works, but only the value of the first textbox is showing up. I read somewhere that [i] will show all the values, but that doesn't seem to work.
What am I doing wrong?
getElementsByClassName
Returns a set of elements which have all the given class names. When called on the document object, the complete document is searched, including the root node. You may also call getElementsByClassName on any element; it will return only elements which are descendants of the specified root element with the given class names.
So you should be doing
var elements = document.getElementsByClassName('output');
var combined = document.getElementById('combined');
for(var i=0; i < elements.length; i++) {
combined.innerHTML += elements[i].value + ",";
}
getElementsByClassName returns an array-like object, not a single element (notice the plural in the name of the function). You need to iterate over it, or use an array index if you just want to operate on the first element it returns:
document.getElementsByClassName('output')[0].value + ","
getElementsByClassName returns a set of elements. You need to iterate over it:
var elems = document.getElementsByClassName("output");
for(var i=0; i<elems.length; i++) {
combined.innerHTML += elems[i].value + ",";
}
That's why adding [0] works, because you are accessing the first object in this set.
This function will return ALL the elements with that name, because"name" attribute is not unique, so it returns an list (nodeList, to be exact).
To print out ALL the values, you need to add a loop. Something like
var finalvar = "";
var arr = document.getElementsByClassName('output');
for (i=0;i<arr.length;i++) {
finalval = finalval + arr[i].value;
}
document.getElementById('combined').innerHTML = finalval
getElementsByClassName will return a set of elements. Refer: https://developer.mozilla.org/en-US/docs/Web/API/document.getElementsByClassName#Summary. Some browsers return HTMLCollection and some browsers return NodeList. https://developer.mozilla.org/en-US/docs/Web/API/HTMLCollection#Browser_compatibility But they both have length property and item method in common. So you can iterate like this.
function doCombine()
{
var listOfOutputElements = document.getElementsByClassName('output');
var combinedItem = document.getElementById('combined');
for (var i = 0; i < listOfOutputElements.length; i += 1) {
combinedItem.innerHTML += listOfOutputElements.item(i).innerHTML;
}
}
Try this :
<script type="text/javascript">
function doCombine()
{
var combined = document.getElementById('combined');
var nodeList = document.getElementsByClassName('output');
var nodeListLength = nodeList.length;
for (i=0;i<nodeListLength;i++) {
combined.innerHTML += nodeList[i] + ',';
}
</script>
getElementsByClassName returns an NodeList. So you won't be able to call the value method on it. Try the following:
function doCombine() {
var combined = document.getElementById('combined');
var outputs = document.getElementsByClassName('output');
for(var i=0; i<outputs.length; i++){
combined.innerHTML += outputs[i].value + ',';
}
}
http://jsfiddle.net/FM3qH/

I want to loop through an array and modify attributes

Here is my code
var input_buttons = ["#one","#two","#three"];
var substr = input_buttons.split(',');
for(var i=0; i< substr.length; i++)
{
substr.attr('value', '');
}
Why doesn't this work?
Your first problem is calling split(',') on an array. However, if you just want to set the values of all those to a blank string you can do:
$('#one,#two,#three').val('');
If you want to set different values you'd need to loop through:
$('#one,#two,#three').each(function() {
// this == the HTML node (not a jQuery element)
this.value = someValue; // someValue would set outside
};
You already have an array, there is nothing to split, this only works on strings. You'd also have to pass the ID to jQuery before you can cal attr. In this case val is even better.
var input_buttons = ["#one","#two","#three"];
for(var i=input_buttons.length; i--;) {
$(input_buttons[i]).val('');
}
But shorter would be using the multiple selector:
$('#one, #two, #three').val('');
or if you already have the array, create a string by joining the IDs:
$(input_buttons.join(',')).val('');
I'm wondering why you are calling:
var substr = input_buttons.split(',');
By the nature of your input_buttons, you already have an array. All you should have to do is:
var input_buttons = ["#one","#two","#three"];
for(var i=0; i< substr.length; i++)
{
$(input_buttons[i]).attr('value', '');
}
var input_buttons = ["#one","#two","#three"];
$.each(input_buttons, function(idx, value) {
$(value).val('');
});
Or even better and shorter:
$('#one, #two, #three').val('');
You could also give those elements a common class name and then use this:
$('.className').val('');
your array contains just the id but not the actual object
try this
var input_buttons = ["#one","#two","#three"];
for(var i=0; i< input_buttons.length; i++)
{
$(input_buttons[i]).removeAttr('value');
}
input_buttons is already an array - don't split it.
To use .attr you need it to be a jquery object, so call $(input_buttons[i]).attr
Try the following to remove an attribute:
var input_buttons = ["#one","#two","#three"];
for(var i=0; i< input_buttons.length; i++)
{
$(input_buttons[i]).removeAttr('value');
}
The reason your code does not work is in the overloading of jQuery functions. .attr('value', '') evaluates to .attr('value'), which returns the value of value as opposed to setting it. The reason is that '' evaluates to false.

Categories

Resources