use remove() on multiple elements - javascript

this: document.getElementsByClassName('warningmessage').remove(); doesn't work if you have multiple warningmessage elements on the page.
How can I just delete all elements with that class? do I have to use a for each? isn't there a command to deleteall()?
thanks for your tips!

With plain JavaScript you can do this:
var nodes = document.getElementsByClassName('warningmessage');
for(var i = 0; i < nodes.length; i++){
nodes[i].parentNode.removeChild(nodes[i]);
}
So you would first of all get the nodes you are interested in and afterwards iterate over them and remove them from their parents.
Sadly there is no forEach method on NodeList. However, you could this:
var nodes = document.getElementsByClassName('warningmessage');
[].forEach.call(nodes, function (node) {
node.parentNode.removeChild(node);
});

You need to use a loop. The below code shows how you write in "normal" javascript.
var elements = document.getElementsByClassName('warningmessage'),
element;
while (element = elements[0]) {
element.parentNode.removeChild(element);
}
The working demo.
​

This would be super easier using JQuery:
$('.warningmessage').remove();
But it's not that hard when you do it without. getElementsByClassName can return a nodelist of items. So you'll just have to loop through the list and remove each item:
var list = document.getElementsByClassName("warningmessage");
for(var i = list.length - 1; i >= 0; i--)
{
var n = list[i];
n.parentNode.removeChild(n);
}

You can try this
var elms= document.getElementsByClassName('warningmessage');
while(elms.length>0){
for(var i = 0; i < elms.length; i++){
elms[i].parentNode.removeChild(elms[i]);
}
}​
http://jsfiddle.net/gBwjA/

I have this problem before and I end up in this algorithm.
function removeElement(target) {
if(target.hasOwnProperty('length')) {
for(i=0; i<target.length; i++) {
removeElement(target[i]);
}
} else {
target.parentNode.removeChild(target);
}
}
and then you call the function like this:
removeElement(document.getElementById('the-id'));
or if you want to remove an HTML collection of elements then you call the function in this way:
removeElement(document.getElementsByTagName('tag-name'));

Related

How to write Javascript to search nodes - without getElementsByClassName

I'm very new at recursion, and have been tasked with writing getElementsByClassName in JavaScript without libraries or the DOM API.
There are two matching classes, one of which is in the body tag itself, the other is in a p tag.
The code I wrote isn't working, and there must be a better way to do this. Your insight would be greatly appreciated.
var elemByClass = function(className) {
var result = [];
var nodes = document.body; //<body> is a node w/className, it needs to check itself.
var childNodes = document.body.childNodes; //then there's a <p> w/className
var goFetchClass = function(nodes) {
for (var i = 0; i <= nodes; i++) { // check the parent
if (nodes.classList == className) {
result.push(i);
console.log(result);
}
for (var j = 0; j <= childNodes; j++) { // check the children
if (childNodes.classList == className) {
result.push(j);
console.log(result);
}
goFetchClass(nodes); // recursion for childNodes
}
goFetchClass(nodes); // recursion for nodes (body)
}
return result;
};
};
There are some errors, mostly logical, in your code, here's what it should have looked like
var elemByClass = function(className) {
var result = [];
var pattern = new RegExp("(^|\\s)" + className + "(\\s|$)");
(function goFetchClass(nodes) {
for (var i = 0; i < nodes.length; i++) {
if ( pattern.test(nodes[i].className) ) {
result.push(nodes[i]);
}
goFetchClass(nodes[i].children);
}
})([document.body]);
return result;
};
Note the use of a regex instead of classList, as it makes no sense to use classList which is IE10+ to polyfill getElementsByClassName
Firstly, you'd start with the body, and check it's className property.
Then you'd get the children, not the childNodes as the latter includes text-nodes and comments, which can't have classes.
To recursively call the function, you'd pass the children in, and do the same with them, check for a class, get the children of the children, and call the function again, until there are no more children.
Here are some reasons:
goFetchClass needs an initial call after you've defined it - for example, you need a return goFetchClass(nodes) statement at the end of elemByClass function
the line for (var i = 0; i <= nodes; i++) { will not enter the for loop - did you mean i <= nodes.length ?
nodes.classList will return an array of classNames, so a direct equality such as nodes.classList == className will not work. A contains method is better.
Lastly, you may want to reconsider having 2 for loops for the parent and children. Why not have 1 for loop and then call goFetchClass on the children? such as, goFetchClass(nodes[i])?
Hope this helps.

How to hide all elements of class?

I found this function:
document.getElementsByClassName = function(c){
for(var i=0,a=[],o;o=document.body.getElementsByTagName('*')[i++];){
if(RegExp('\\b'+c+'\\b','gi').test(o.className)){
a.push(o);
}
}
return a;
}
How can I hide all elements by class?
I tried:
var array = document.getElementsByClassName("hide");
for(var i = 0; i < array.length; i++)
{
$(array[i]).hide();
}
But I got error:
Could not convert JavaScript argument arg 0 [nsIDOMWindow.getComputedStyle]
jQuery allows CSS selectors to be used, doing away with the need for hand-built loops and regular expressions. To hide an element with class fooey, just do
$('.fooey').hide();
If you're using vanilla JavaScript, then:
var array = document.getElementsByClassName("hide");
for(var i = 0; i < array.length; i++)
{
array[i].style.display = 'none';
array[i].onclick = function(){
// do stuff
};
/* or:
array[i].addEventListener('click',functionToCall);
*/
}
But, given that you're using jQuery, I don't understand why you're complicating things for yourself, just use:
$('.hide').hide();
Further to the above, given your comment:
Because I must add event "click" for each element.
Simply use:
$(elementSelector).click(
function(){
// do stuff
});
Assuming you want to hide, and bind a click-event to, the same elements:
$('.hide').hide().click(
function(){
// do stuff
});
What you get from getElementsByClassName is NOT an array, but a NodeList, hence the error when trying to loop.
However, you can still loop over a NodeList using the following:
var nodeList = document.getElementsByClassName("hide");
for(var x in nodeList){}

Need help finding/traversing dom in Javascript

I'm sure this is a redundant question, but I've looked for an hour or so and come up empty-handed so was hoping someone could help...
Looking for a way to use JS (not jquery) to return the class of the li below when searching for 'Chicken' (or whatever the value is).
<li class='113252'>
<span>Chicken</span>
</li>
So was hoping the javascript would return the li class when given the span value (in this case Chicken).
Thanks!
Try this:
var spanArray = document.getElementsByTagName('span');
for (var i=0; i<spanArray.length; i++) {
if(spanArray[i].innerHTML.toUpperCase() === 'CHICKEN')
{
alert(spanArray[i].parentNode.className);
break;
}
}
Now, I'm more familiar with jQuery but seems to work in the fiddle linked here: http://jsfiddle.net/FranWahl/fCzYc/2/ (Updated to include suggested break; after match)
You can add more type checking for the parentNode to ensure it is an li and so on, but this should get you started.
Also, I'm not sure at all how efficient this is in a big document.
Edit
Having read through some comments I have updated my code above to include the break as suggested by ajax333221.
Dennis mentioned that it would be better to call getElementByTagName on the ul.
Given you can have an li without a ul I added it here as separate code as I'm not sure if the OP has ul tags.
Code querying against each ul (jsFiddle here)
var ulArray = document.getElementsByTagName('ul');
var parentFound = false;
for (var i = 0; i < ulArray.length; i++) {
var spanArray = ulArray[i].getElementsByTagName('span');
for (var i = 0; i < spanArray.length; i++) {
if (spanArray[i].innerHTML.toUpperCase() === 'CHICKEN') {
alert(spanArray[i].parentNode.className);
parentFound = true;
break;
}
}
if(parentFound)
{
break;
}
}​
This is by no means fully complete, which is why you should seek a library, but it does two things:
recursively traverse child elements (starting with the document's BODY), to find the supplied text
recursively traverse the parent element to find the supplied parent element tag, once found it will return the class of that parent
JSFiddle: http://jsfiddle.net/vol7ron/bttQN/
function getParentClass(element, parentTag){
if (element.tagName == parentTag.toUpperCase())
return element.className;
return getParentClass(element.parentNode,parentTag);
}
window.findParentClass = function (text,tagName){
var elements = document.getElementsByTagName('body');
for (var n=elements.length; n--;){
var foundClass = (function searchNextChild(el){
if (!el.children.length) {
if (el.textContent == text)
return getParentClass(el,tagName);
return;
}
for (var i=0, n=el.children.length; i<n; i++)
return searchNextChild(el.children[i]);
})(elements[n]);
return foundClass;
}
};
Example Call:
alert( findParentClass('Chicken','li') );

How to get all childNodes in JS including all the 'grandchildren'?

I want to scan a div for all childNodes including the ones that are nestled within other elements. Right now I have this:
var t = document.getElementById('DivId').childNodes;
for(i=0; i<t.length; i++) alert(t[i].id);
But it only gets the children of the Div and not the grandchildren. Thanks!
Edit: This question was too vague. Sorry about that. Here's a fiddle:
http://jsfiddle.net/F6L2B/
The body.onload script doesn't run at JSFiddle, but it works, except that the 'Me Second' and 'Me Third' input fields are not being assigned a tabIndex and are therefore being skipped over.
This is the fastest and simplest way, and it works on all browsers:
myDiv.getElementsByTagName("*")
If you're looking for all HTMLElement on modern browsers you can use:
myDiv.querySelectorAll("*")
What about great-grandchildren?
To go arbitrarily deep, you could use a recursive function.
var alldescendants = [];
var t = document.getElementById('DivId').childNodes;
for(let i = 0; i < t.length; i++)
if (t[i].nodeType == 1)
recurseAndAdd(t[i], alldescendants);
function recurseAndAdd(el, descendants) {
descendants.push(el.id);
var children = el.childNodes;
for(let i=0; i < children.length; i++) {
if (children[i].nodeType == 1) {
recurseAndAdd(children[i]);
}
}
}
If you really only want grandchildren, then you could take out the recursion (and probably rename the function)
function recurseAndAdd(el, descendants) {
descendants.push(el.id);
var children = el.childNodes;
for(i=0; i < children.length; i++) {
if (children[i].nodeType == 1) {
descendants.push(children[i].id);
}
}
}
If anyone else wants all nodes within that tree, and not just the elements, here's a 2022-era JS snippet:
function getDescendantNodes(node, all = []) {
all.push(...node.childNodes);
for (const child of node.childNodes)
getDescendantNodes(child, all);
return all;
}
Protip: afterwards, you can filter to your preferred nodeType with the Node global: nodes = getDescendantNodes($0); nodes.filter(n => n.nodeType === Node.TEXT_NODE)

How do I make this loop all children recursively?

I have the following:
for (var i = 0; i < children.length; i++){
if(hasClass(children[i], "lbExclude")){
children[i].parentNode.removeChild(children[i]);
}
};
I would like it to loop through all children's children, etc (not just the top level). I found this line, which seems to do that:
for(var m = n.firstChild; m != null; m = m.nextSibling) {
But I'm unclear on how I refer to the current child if I make that switch? I would no longer have i to clarify the index position of the child. Any suggestions?
Thanks!
Update:
I'm now using the following, according to answer suggestions. Is this the correct / most efficient way of doing so?
function removeTest(child) {
if (hasClass(child, "lbExclude")) {
child.parentNode.removeChild(child);
}
}
function allDescendants(node) {
for (var i = 0; i < node.childNodes.length; i++) {
var child = node.childNodes[i];
allDescendants(child);
removeTest(child);
}
}
var children = temp.childNodes;
for (var i = 0; i < children.length; i++) {
allDescendants(children[i]);
};
function allDescendants (node) {
for (var i = 0; i < node.childNodes.length; i++) {
var child = node.childNodes[i];
allDescendants(child);
doSomethingToNode(child);
}
}
You loop over all the children, and for each element, you call the same function and have it loop over the children of that element.
Normally you'd have a function that could be called recursively on all nodes. It really depends on what you want to do to the children. If you simply want to gather all descendants, then element.getElementsByTagName may be a better option.
var all = node.getElementsByTagName('*');
for (var i = -1, l = all.length; ++i < l;) {
removeTest(all[i]);
}
There's no need for calling the 'allDescendants' method on all children, because the method itself already does that. So remove the last codeblock and I think that is a proper solution (á, not thé =])
function removeTest(child){
if(hasClass(child, "lbExclude")){
child.parentNode.removeChild(child);
}
}
function allDescendants (node) {
for (var i = 0; i < node.childNodes.length; i++) {
var child = node.childNodes[i];
allDescendants(child);
removeTest(child);
}
}
var children = allDescendants(temp);
You can use BFS to find all the elements.
function(element) {
// [].slice.call() - HTMLCollection to Array
var children = [].slice.call(element.children), found = 0;
while (children.length > found) {
children = children.concat([].slice.call(children[found].children));
found++;
}
return children;
};
This function returns all the children's children of the element.
The most clear-cut way to do it in modern browsers or with babel is this. Say you have an HTML node $node whose children you want to recurse over.
Array.prototype.forEach.call($node.querySelectorAll("*"), function(node) {
doSomethingWith(node);
});
The querySelectorAll('*') on any DOM node would give you all the child nodes of the element in a NodeList. NodeList is an array-like object, so you can use the Array.prototype.forEach.call to iterate over this list, processing each child one-by-one within the callback.
If you have jquery and you want to get all descendant elements you can use:
var all_children= $(parent_element).find('*');
Just be aware that all_children is an HTML collection and not an array. They behave similarly when you're just looping, but collection doesn't have a lot of the useful Array.prototype methods you might otherwise enjoy.
if items are being created in a loop you should leave a index via id="" data-name or some thing. You can then index them directly which will be faster for most functions such as (!-F). Works pretty well for 1024 bits x 100 items depending on what your doing.
if ( document.getElementById( cid ) ) {
return;
} else {
what you actually want
}
this will be faster in most cases once the items have already been loaded. only scrub the page on reload or secure domain transfers / logins / cors any else and your doing some thing twice.
If you use a js library it's as simple as this:
$('.lbExclude').remove();
Otherwise if you want to acquire all elements under a node you can collect them all natively:
var nodes = node.getElementsByTagName('*');
for (var i = 0; i < nodes.length; i++) {
var n = nodes[i];
if (hasClass(n, 'lbExclude')) {
node.parentNode.removeChild(node);
}
}
To get all descendants as an array, use this:
function getAllDescendants(node) {
var all = [];
getDescendants(node);
function getDescendants(node) {
for (var i = 0; i < node.childNodes.length; i++) {
var child = node.childNodes[i];
getDescendants(child);
all.push(child);
}
}
return all;
}
TreeNode node = tv.SelectedNode;
while (node.Parent != null)
{
node = node.Parent;
}
CallRecursive(node);
private void CallRecursive(TreeNode treeNode)
{
foreach (TreeNode tn in treeNode.Nodes)
{
//Write whatever code here this function recursively loops through all nodes
CallRecursive(tn);
}
}

Categories

Resources