how to concatenate two getElementsBy - javascript

I have a snippet of code like this:
var profileLinks = new Array();
for (var i = 0; i<searchResult.length; ++i)
{
var profileLink=searchResult[i].getElementsByTagName("a");
profileLinks[i]=profileLink[0].href;
alert(i+1+" of "+searchResult.length+" "+profileLinks[i]);
}
It seems like I should be able to make it more concise by using this:
//alternate construction (why doesn't this work?)
var searchResult = document.getElementsByClassName("f_foto").getElementsByTagName("a");
What's wrong here?

Use querySelectorAll() instead:
var searchResult = document.querySelectorAll(".f_foto a");
IE 8 supports querySelectorAll() but not getElementsByClassName(), so this should give you better compatibility too.
For full compatibility, stick to your original code or use a library like jQuery.

document.getElementsByClassName("f_foto")
returns a selection, therefore you cannot chain functions to it. You need to specify an element directly not a whole selection, for example this would work correctly.
document.getElementsByClassName("f_foto")[0].getElementsByTagName("a");
Because document.getElementsByClassName("f_foto")[0] points to an object and not to a selection of objects.

This is why we have libraries - or even modern browsers. You are looking for the css selector $('.f_foto a') in jQuery, or $$('.f_foto a') in Prototoype/Chrome

You call getElementsByTagName on a node, not an array, which is what is returned by getElementsByClassName.

I believe that getElementsByTagName can only be applied to an element node, but the result of getElementsByClassName is surely going to be a list of nodes. You'll either have to pick one ([0]?) or iterate over the collection (make sure it's not empty!).

Related

Get visible from jQuery collection of objects

I have this line of code:
var filterInputs = $(this).siblings('.filterInputs');
which performs some work on filterInputs. Later on, I would like to reduce my collection of filterInputs to just those which are visible.
Clearly, I could do this:
var visibleFilterInputs = $(this).siblings('.filterInputs:visible');
but that seems inefficient given the fact that I already have a reference to the collection I was hoping to reduce.
Is there a way to say something like:
//TODO: Example
var visibleFilterInputs = $(filterInputs:visible);
without having to iterate over the DOM tree again? Thanks
You're absolutely right, there's no reason to recollect the DOM elements, since you already have them in a jQuery object. So that's exactly what the .filter() method is for: http://api.jquery.com/filter/
Try this:
var visibleFilterInputs = filterInputs.filter(":visible");
Here's an example: http://jsfiddle.net/FC9sH/
Note that it's better to target a certain HTML tag, such as <div>, to make the :visible selector a little more efficient (since it isn't part of the CSS specs and can't be optimized by native methods). At least in your case, you're already using the filterInputs class. Anyways, maybe something like:
var visibleFilterInputs = filterInputs.filter("div:visible");
but only if that's applicable. I mean, even selecting multiple known element tags is probably better:
var visibleFilterInputs = filterInputs.filter("div:visible, p:visible");

Clear element.classList

element.classList is of DOMTokenList type.
Is there a method to clear this list?
I'm not aware of a "method" in the sense of a "function" associated with classList. It has .add() and .remove() methods to add or remove individual classes, but you can clear the list in the sense of removing all classes from the element like this:
element.className = "";
With ES6 and the spread operator, this is a breeze.
element.classList.remove(...element.classList);
This will spread the list items as arguments to the remove method.
Since the classList.remove method can take many arguments, they all are removed and the classList is cleared.
Even though it is readable it is not very efficient. #Fredrik Macrobond's answer is faster.
View different solutions and their test results at jsperf.
var classList = element.classList;
while (classList.length > 0) {
classList.remove(classList.item(0));
}
Here's another way to do it:
element.setAttribute("class", "")
Nowadays, classList is preferred to (remove|set)Attribute or className.
Pekaaw's answer above is good, 1 similar alternative is to set the DomTokenList.value
elem.classList.value = ''
Another option is to simply remove the class attribute:
elem.removeAttribute('class')
I recommend not using className as classList could result in faster DOM updates.
The remove() method of DOMTokenList (which is what classList is) can take multiple arguments - each a string of a classname to remove (reference). First you need to convert the classList to a plan array of classnames. Some people use Array.prototype.slice() to do that, but I'm not a fan and I think a for loop is faster in most browsers - but either way I have nothing against for loops and the slice often feels like a hack to me. Once you have the array you simply use apply() to pass that array as a list of arguments.
I use a utility class I wrote to accomplish this. The first method is the one you are looking for, but I'm including slightly more for your reference.
ElementTools.clearClassList = function(elem) {
var classList = elem.classList;
var classListAsArray = new Array(classList.length);
for (var i = 0, len = classList.length; i < len; i++) {
classListAsArray[i] = classList[i];
}
ElementTools.removeClassList(elem, classListAsArray);
}
ElementTools.removeClassList = function(elem, classArray) {
var classList = elem.classList;
classList.remove.apply(classList, classArray);
};
ElementTools.addClassList = function(elem, newClassArray) {
var classList = elem.classList;
classList.add.apply(classList, newClassArray);
};
ElementTools.setClassList = function(elem, newClassArray) {
ElementTools.clearClassList(elem);
ElementTools.addClassList(elem, newClassArray);
};
Please note that I have not thoroughly tested this in all browsers as the project I am working on only needs to work in a very limited set of modern browsers. But it should work back to IE10, and if you include a shim (https://github.com/eligrey/classList.js) for classList, it should work back to IE7 (and also with SVGs since Eli Grey's shim adds support for SVG in unsupported browsers too).
An alternative approach I considered was to loop backwards through the classList and call remove() on classList for each entry. (Backwards because the length changes as you remove each.) While this should also work, I figured using the multiple arguments on remove() could be faster since modern browsers may optimize for it and avoid multiple updates to the DOM each time I call remove() in a for loop. Additionally both approaches require a for loop (either to build a list or to remove each) so I saw no benefits to this alternative approach. But again, I did not do any speed tests.
If somebody tests speeds of the various approaches or has a better solution, please post.
EDIT: I found a bug in the shim which stops it from correctly adding support to IE11/10 for multiple arguments to add() and remove(). I have filed a report on github.

How to remove all elements of a certain class from the DOM?

var paras = document.getElementsByClassName('hi');
for (var i = 0; i < paras.length; i++) {
paras[i].style.color = '#ff0011';
// $('.hi').remove();
}
<p class="hi">dood</p>
<p class="hi">dood</p>
<p class="hi">dood</p>
<p class="hi">dood</p>
<p class="hi">dood</p>
<p>not class 'hi'</p>
In jQuery, this would be very easy: $('.hi').remove();. I want to learn JS, and then jQuery.
I am stuck and Google has not provided. I do not want to become a copy/paste jQuery programmer. I am just starting to learn JS. Thanks.
To remove an element you do this:
el.parentNode.removeChild(el);
MDN is a great reference. Here are a few relevant pages:
Node
parentNode
removeChild
However you'll run into issues if you loop like that since getElementsByClassName returns a live list, when you remove a node the element is removed from the list as well so you shouldn't increment or you will end up skipping every other element. Instead just continually remove the first element in the list, until there is no first element:
var paras = document.getElementsByClassName('hi');
while(paras[0]) {
paras[0].parentNode.removeChild(paras[0]);
}​
IMO jQuery is great at showing you what is possible to do in Javascript. I actually recommend that after about a week or two of plain JS you learn jQuery, get good at it, and remember what it's abstracting away. One day when you have an excellent grasp of Javascript scoping, objects, and such which you can obtain while using jQuery, go back and try learning how to interact better with the DOM without a library. That way you'll have an easier time learning plain JS and you'll appreciate the abstraction that libraries can provide you even more, while learning that when you only need one or two things a library provides you may be able to write them yourself without including the entire library.
Simple ES6 answer:
document.querySelectorAll('.classname').forEach(e => e.remove());
Explanation:
document.querySelectorAll() loops through the elements in the document returning a NodeList of all elements with the specified selector (e.g. '.class', '#id', 'button')
forEach() loops through the NodeList and executes the specified action for each element
e => e.remove() removes the element from the DOM
Note, however, that this solution is not supported by Internet Explorer. Then again, nothing is.
[].forEach.call(document.querySelectorAll('.hi'),function(e){
e.parentNode.removeChild(e);
});
Here I'm using Array.prototype.forEach to easily traverse all elements in an array-like object, i.e. the static NodeList returned by querySelectorAll, and then using removeChild() to remove the item from the DOM.
For older browsers that don't support querySelectorAll() or forEach():
var classMatcher = /(?:^|\s)hi(?:\s|$)/;
var els = document.getElementsByTagName('*');
for (var i=els.length;i--;){
if (classMatcher.test(els[i].className)){
els[i].parentNode.removeChild(els[i]);
}
}
Note that because getElementsByTagName returns a live NodeList, you must iterate over the items from back to front while removing them from the DOM.
There are also some older browsers that don't support querySelectorAll but that do support getElementsByClassName, which you could use for increased performance and reduced code.
Afaik only a parent can remove a child in native JS. So you would first have to get that elements parent, then use the parent to remove the element. Try this:
var parent = paras[i].parentNode;
parent.removeChild(paras[i]);

getElementById() wildcard

I got a div, and there i got some childnodes in undefined levels.
Now I have to change the ID of every element into one div. How to realize?
I thought, because they have upgoing IDs, so if the parent is id='path_test_maindiv' then the next downer would be 'path_test_maindiv_child', and therefore I thought, I'd solve that by wildcards, for example:
document.getElementById('path_test_*')
Is this possible? Or are there any other ways?
Not in native JavaScript. You have various options:
1) Put a class and use getElementsByClassName but it doesn't work in every browser.
2) Make your own function. Something like:
function getElementsStartsWithId( id ) {
var children = document.body.getElementsByTagName('*');
var elements = [], child;
for (var i = 0, length = children.length; i < length; i++) {
child = children[i];
if (child.id.substr(0, id.length) == id)
elements.push(child);
}
return elements;
}
3) Use a library or a CSS selector. Like jQuery ;)
In one of the comments you say:
(...) IE is anyway banned on my page, because he doesn't get it with CSS. It's an admin tool for developer, so only a few people, and they will anyway use FF
I think you should follow a different approach from the beginning, but for what it's worth, in the newer browsers (ok, FF3.5), you can use document.querySelectorAll() with which you can get similar results like jQuery:
var elements = document.querySelectorAll('[id^=foo]');
// selects elements which IDs start with foo
Update: querySelectorAll() is only not supported in IE < 8 and FF 3.0.
jQuery allows you to find elements where a particular attribute starts with a specific value
In jQuery you would use
$('[id^="path_test_"]')
Try this in 2019 as a wildcard.
document.querySelectorAll("[id*=path_test_]")
I don't think so wildcards are allowed in getelementById.
Instead you can have all the child nodes of your respective DIV using:
var childNodeArray = document.getElementById('DIVID').childNodes;
This'll give you an array of all elements inside your DIV. Now using for loop you can traverse through all the child elements and simultaneously you can check the type of element or ID or NAME, if matched then change it as you want.
You should not change ID of element to ID of other existing element. It's very wrong, so you better re-think your core logic before going on.
What are you trying to do exactly?
Anyway, to get all elements with ID starting with something, use jQuery as suggested before, if you can't it's also possible using pure JavaScript, let us know.

Prototype get by tag function

How do I get an element or element list by it's tag name. Take for example that I want all elements from <h1></h1>.
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
document.getElementsByTagName('a') returns an array. Look here for more information: http://web.archive.org/web/20120511135043/https://developer.mozilla.org/en/DOM/element.getElementsByTagName
Amendment: If you want a real array, you should use something like Array.from(document.getElementsByTagName('a')), or these days you'd probably want Array.from(document.querySelectorAll('a')). Maybe polyfill Array.from() if your browser does not support it yet. I can recommend https://polyfill.io/v2/docs/ very much (not affiliated in any way)
Use $$() and pass in a CSS selector.
Read the Prototype API documentation for $$()
This gives you more power beyond just tag names. You can select by class, parent/child relationships, etc. It supports more CSS selectors than the common browser can be expected to.
Matthias Kestenholz:
getElementsByTagName returns a NodeList object, which is array-like but is not an array, it's a live list.
var test = document.getElementsByTagName('a');
alert(test.length); // n
document.body.appendChild(document.createElement('a'));
alert(test.length); // n + 1
You could also use $$(tag-name)[n] to get specific element from the collection.
If you use getElementsByTagName, you'll need to wrap it in $A() to return an Array. However, you can simply do $$('a') as nertzy suggested.

Categories

Resources