getElementsByTagName from a collection - javascript

EDIT: the document.querySelectorAll solution works, and is easier to read and understand. My own solution (in the answers, below) also works, and is slightly faster. The getElementsByClassName + getElementsByClassName solution is the fastest, so I've marked it as the accepted solution.
ORIGINAL POST: I need to find child elements of any element with a particular class, e.g.,
<li class="myclass"><a>This is the link I need to find</a></li>
so that I can set and remove some attributes from the anchor.
I can easily find all of the list items with getElementsByClassName, but getElementsByTagName fails because it only works on a single declared element (not on a collection). Therefore, this does not work:
const noLinks = document.getElementsByClassName('myclass');
for (let noLink of noLinks) {
const matches = noLinks.getElementsByTagName('a');
matches.setAttribute('role', 'link');
matches.setAttribute('aria-disabled', 'true');
matches.removeAttribute('href');
matches.removeAttribute('rel');
};
How can I iterate through the returned elements and get the tags inside of them?

The problem is in getElementsByTagName which returns a live HTMLCollection of elements, Your matches variable contains an array whereas must be an element to apply to him some properties href, rel..., So he needs to be an element not elments, To solve the problem just access to the first element not all of them, or use querySelector which return the first matched element if exist.
const noLinks = document.getElementsByClassName('myclass');
for (let noLink of noLinks) {
//v-- access to noLink not noLinks
const matches = noLink.getElementsByTagName('a')[0]; //<-- or noLinks.querySelector('a')
matches.setAttribute('role', 'link');
matches.setAttribute('aria-disabled', 'true');
matches.removeAttribute('href');
matches.removeAttribute('rel');
};

The OP's code could be switched to something more expressive (based on e.g. querySelectorAll) like ...
document
.querySelectorAll('.myclass a')
.forEach(elmNode => {
elmNode.setAttribute('role', 'link');
elmNode.setAttribute('aria-disabled', 'true');
elmNode.removeAttribute('href');
elmNode.removeAttribute('rel');
});

The following solution works. I'll probably test the other 2 offered solutions & upvote them if they work, but I'm posting this answer so others can see different ways of solving this.
// Modify the attributes on the <a> inside the <li> with class "nolink".
const noLinks = document.getElementsByClassName('nolink');
Array.prototype.forEach.call(noLinks, function(noLink) {
const matches = noLink.getElementsByTagName('a')[0];
matches.setAttribute('role', 'link');
matches.setAttribute('aria-disabled', 'true');
matches.removeAttribute('href');
matches.removeAttribute('rel');
});

Related

Why does my function return undefined, especially the .split()parts?

So in essence I get the value of input, then try to divide into into different tags via the comma with this
var noteTags = document.getElementsByClassName("noteTag").value;
Tag = noteTags.split(",");
But in console, the split(",") is undefined
Edit: Sorry I forgot to mention that the noteTag element is input, does this change how the code works in any way?
There are two issues,
getElementsByClassName returns an array-like collection of elements (a NodeList).
And instead of value it should be innerText.
Try like below
var noteTags = document.getElementsByClassName("noteTag")[0].innerText;
Tag = noteTags.split(",");
You are using the split() method on an array. You are also trying to access the value property, whereby you should probably use innerText.
You can use querySelector then you dont need using a key[0] to select the element.
const noteTags = document.querySelector("#noteTag");
console.log(noteTags)
Tag = noteTags.innerHTML.split(",");
console.log(Tag)
<div id="noteTag">en,jp,fr</div>

Get element by a word it contains

Is there a way to get an element by its content(a word it contains?)
For example, get all the elements with the letter "F," and put it in a array of elements
I highly recommand you to use jQuery for these kind of DOM elements searching.
Then you can use this:
var foos = $("div:contains('foo')" )
will make an array with all divs containing the word 'foo'.
One fairly easy way is to select the elements you're interested in and then use 'filter' to look at the innerText. You can make this case insensitive with toLowerCase
var result = $('div').filter( (i,e) => e.innerText.toLowerCase().indexOf("f")>-1);
console.log("Items with 'F':",result.length);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>Forest</div>
<div>Fortnight</div>
<div>Trees</div>
<div>Africa</div>
The simpler way is using :contains('F') as a selector - but that is always case sensitive (which may be fine for your case).
You can use :contains as a selector. For example, to filter all divs of a special class that also contains your text, you can use $("div.myclass:contains('searched text')")
I think you can "bruteforce" it by iterating all DOM items. e.g.:
let arrayDom = Array.from(document.getElementsByTagName("*"));
arrayDom.forEach(element => {
if (element.innerHTML.contains('F')){
// Do something
}
})

After click show element in console

I need a help. I have a button in html with class "rekapitulace". And i want to do if a user click on that button, it will show a item in text input with class "jmeno". I wrote this but it isnt correct. Any solutions?
function rekapitulaceButton() {
var rekapitulaceButton = document.getElementsByClassName('rekapitulace')
rekapitulaceButton.addEventListener('click', precistUdaje)
}
function precistUdaje() {
var jmeno = document.getElementsByClassName('jmeno')
localStorage.setItem('local-jmeno', jmeno)
console.log(localStorage.getItem('local-jmeno'))
}
getElementsByClassName() returns all elements of provided class name, not just a single element. Notice how the name of that method contains plural elements word.
To get the first element, you can do:
const rekapitulaceButton = document.getElementsByClassName('rekapitulace')[0];
Another possibility is document.querySelector(), which always returns one element (first match) or null:
const rekapitulaceButton = document.querySelector('.rekapitulace');
document.getElementsByClassName('rekapitulace') return a nodelist array so if you need return an one node elment using id instead of class
document.getElementById('rekapitulace')
Note that you may be misusing localStorage for your debugging. The second argument of .set should be a string.
As mentioned already, you should really try to use IDs instead of classes for targeting the right input, and document.getElementsByClassName returns multiple elements and not just one element.

Mootools Selector issue

Right now I have a dynamic string that assigns it's values to a particular div class.
Output looks like this
<div class="12923"></div>
I want to find that 'randNumber' div, then check if it has another class 'x'
Currently what I have now doesn't work:
var randNumber = 12923
var lookingForYou = $$('.'+randNumber);
if (lookingForYou.hasClass('XCLASS')){alert('XCLASS FOUND!');}
$$ returns an Elements instance, Elements is an array-like Class
anyway since you are basically filtering, you can tell Slick that you need an element with both class:
var randNumber = 12923;
if($$('.' + randNumber +'.XCLASS').length>0){
alert('XCLASS FOUND');
}else{
//dostuff
}
or you could just use one of the Elements methods, I think .some will be your best choice here:
var randNumber = 12923
var lookingForYou = $$('.' + randNumber);
alert(lookingForYou.some(function(el){
return el.hasClass('XCLASS');
}))
EDIT:
adding some links:
A better way to use Elements on MooTools blog
in my second example I used the some method, which, by looking at the source is not overloaded, but is just the one in Array.prototype.some:
Element.js source reference
Array.some on MDN
$$ returns an array of all matching elems. Not sure if you can do a hasclass on an array. Might have to do a .each() then do it. Try $('body').getElement('.'+randNumber).hasClass('XCLASS') this way you grab 1 elem if you don't want to mess with the array.
Here:
if (lookingForYou.hasClass('XCLASS')){alert('XCLASS FOUND!');}
$$() returns an array, and hasClass() performs the check on each element of the array, returning an array of booleans. Unfortunately, when you check if (...), then the return array, even if all of the values are false, is evaluated as true because it's non-empty.

How to make Javascript more specific?

I am new at JavaScript so I think my problem may be simple.
This works:
var convId = document.getElementById("wrapper");
convId.setAttribute("align","right");
But when I try to make it more specific:
var convId = document.getElementById("wrapper");
var convIdDl = convId.getElementsByTagName("dl");
convIdDl.setAttribute("align","right");
my definition list doesn't align to the right.
I have checked the HTML and CSS and everything is correct, but that shouldn't even matter
JavaScript overwrites them both.
The getElementsByTagName method returns a collection (to be more specific, a NodeList). You need to specify which element of that collection you want to use (just like you would when accessing an element in an array). Here I'm assuming you want the first:
convIdDl[0].setAttribute("align", "right");
As noted in the comments, you should definitely not be using the align attribute. CSS should be used in all cases.
The getElementsByTagName() function returns a collection of DOM elements, so you'll probably want to iterate through that and set the attribute on each element individually.
for(var i = 0; i < convIdDl.length; i++) {
convIdDl[i].setAttribute("align", "right");
}

Categories

Resources