I tried this code to remove every other element in the body, but it didn't work.
s = document.body.childNodes;
for (var i = 1; i < (s.length / 2); i++) {
if ((i % 2) == 0) {
document.body.removeChild(s[1]);
} else {
document.body.removeChild(s[0]);
}
}
<body>
<div id="div1"></div>
<div id="div2"></div>
<div id="div3"></div>
<div id="div4"></div>
<div id="div5"></div>
<div id="div6"></div>
</body>
There are a number of problems with your code. For one thing the logic is off, but there are some major problems with how the code deals with the DOM manipulations:
Your HTML causes text nodes to be created between your elements. And your code does not handle this.
The childNodes list changes as you remove nodes from the parent element.
With this HTML:
<div id="test-container">
<div id="div1">1</div>
<div id="div2">2</div>
<div id="div3">3</div>
<div id="div4">4</div>
<div id="div5">5</div>
<div id="div6">6</div>
</div>
And this JavaScript:
var container = document.getElementById("test-container");
var child = container.firstElementChild;
var remove = true;
while (child) {
var next = child.nextElementSibling;
if (remove)
container.removeChild(child);
remove = !remove;
child = next;
}
I can remove every other child. I avoid both problems I pointed out earlier by using firstElementChild and nextElementSibling.
First, you need to get the elements using children or querySelectorAll() not childNodes, childNodes will get all nodes including the text. Try the following code:
var s = document.body.children;
var itemCount = s.length;
for (var i = 0; i < itemCount; i++)
{
if (i % 2 !== 0)
{
document.body.removeChild(s[i]);
}
}
Here is a JSBin example.
Note that in JSBin we get the elements using querySelectorAll(), beacuse it also adds script elemets inside the body, for example:
var s = document.querySelectorAll('div');
Also, note that IE8 and below includes comment nodes when using children.
You need to know that a nodeList will update when the dom is updated, that means that if you are removing the first child node, the element 0 in the list will not refer to null but the node that was initial child 1.
This means that if you want to remove node 0, 2, 4, 6, ... you will actually have to remove 0,1,2,3,4... (because the nodeList always will update):
var body = document.body;
// Consider that you might want to use `body.children` instead of
// `body.childNodes` because it excludes all text nodes
var nodes = body.childNodes;
var len = nodes.length / 2;
for ( var i = 0; i < len; i++ ) {
body.removeChild(nodes[i]);
}
I know it can seams kind of odd, but this will actually remove all the nodes: 0, 2, 4, 6, ...
See more at MDN
I'd just use querySelectorAll with a :nth-child(odd) selector:
var divs = document.querySelectorAll('body > div:nth-child(odd)');
divs = [].slice.call(divs); // convert from NodeList to real array
divs.forEach(function(elem) {
document.body.removeChild(elem);
});
jsFiddle
Why not use jQuery and simply do:
$('.remOdd').on('click', function(){
$('div').filter(':odd').remove();
})
http://jsfiddle.net/dh5uymzL/
Or of course use ":even" if you like
http://api.jquery.com/filter/
Related
Only JS no Jquery.
How to get All ChildNodes of container and than for each of the children get there children?
I don't want to add ID to each Wrapper that is child of grid-row, I am trying to target with "this" or at this index. This script should be dynamic without specifying any ID.
I can't use classes to get all Wrappers as I need to trigger each wrapper separately and apply changes to it.
I want to get all grid-row children "Wrapper" widths and store in a array.
I am using ChildNodes as it is compatible with all browsers.
var container = document.getElementById('container');
var rows = container.childNodes;
var rowslenght = container.childNodes.length;
var rowsArray = new Array();
for (var i=0; i < rowslenght ; i++) {
if (gridrow[i].nodeType == 1){ // this is to no retrieve text
// I got all the children of grid-row. How I get grid-row children.
// var rowsChildren = rows[i].getAttribute('id');
// here goes other if to go through each "Wrapper" width and set width
// console.log( rowsChildren);
console.log( rows);
return rowsArray;
}
}
<div id="container">
<div class="grid-row">
<div class="Wrapper">
<div class="block"></div>
</div>
<div class="Wrapper">
<div class="block"></div>
</div>
</div>
<div class="grid-row">
<div class="Wrapper">
<div class="block"></div>
</div>
<div class="Wrapper">
<div class="block"></div>
</div>
</div>
</div>
Try this.
var container = document.getElementById('container');
var rows = container.childNodes;
rows = removeTextNode(rows); // remove Text Nodes;
// Loop through .grid-row
forEach(rows, function(row){
// Get wrappers and filter them
var rowWrappers = row.childNodes;
rowWrappers = removeTextNode(rowWrappers);
// Now loop over the wrapper, and modify
// the current function adds `Wrapper-blue` to the wrappers.
forEach(rowWrappers, function(wrapper){
console.log(wrapper);
wrapper.classList += ' Wrapper-blue';
});
});
// this helper function removes extra spaces/breaklines which are considered as Nodes
function removeTextNode(nodes){
return [].filter.call(nodes, function(o){
return o.nodeType == Node.ELEMENT_NODE;
});
}
// Source: https://css-tricks.com/snippets/javascript/loop-queryselectorall-matches/
function forEach(array, callback, scope) {
for (var i = 0; i < array.length; i++) {
// the first argument is thisArg which is the context and can used as `this` in the callback
callback.call(scope, array[i], i); // passes back stuff we need
}
};
.Wrapper-blue {
background:#ddd;
margin:5px;
width:60px;
height:60px;
}
<div id="container">
<div class="grid-row">
<div class="Wrapper">
<div class="block"></div>
</div>
<div class="Wrapper">
<div class="block"></div>
</div>
</div>
<div class="grid-row">
<div class="Wrapper">
<div class="block"></div>
</div>
<div class="Wrapper">
<div class="block"></div>
</div>
</div>
</div>
rows[i].childNodes will give you the Wrapper elements inside each grid-row, but then you will have to loop through them, too.
I was not able to get the second loop right as in the first loop I got all the childNodes including the empty text fields. I needed first to run the the for statement and than only filter the ones that has nodeType == 1.
var container = document.getElementById('container');
var rows = container.childNodes;
var rowslenght = container.childNodes.length;
var rowsArray = new Array();
// Get all the grid-row and run through them
for (var a=0; a < rowslenght ; a++) {
// If it is a HTML element than go through
if (gridrow[a].nodeType == 1){
var wpChildren = gridrow[a].childNodes;
var wpChildrenleght = gridrow[a].childNodes.length;
// Run through all the wrappers
for (var b =0; b < wpChildrenleght; b++){
// only get grid-wrapper html
if (wpChildren[b].nodeType == 1){
console.log(wpChildren[b]) // here is your specific div
}
}
}
}
This isn't as hard as you're making it; you don't have to do multiple loops.
The below is supported by all modern browsers, including IE 9+ https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementsByClassName
var container = document.getElementById('container');
var rows = container.getElementsByClassName('grid-row');
// NOTE: this assumes that you only want to get wrappers which are children of grid-rows which are children of a container
var wrapperChildren = [];
rows.forEach(function(row) {
var wrappers = row.getElementsByClassName('Wrapper');
// per comments, adding child count
row['data-child-count'] = wrappers.length;
wrapperChildren.concat(wrappers);
});
It gets easier still if the wrappers are only inside grid-rows already (then you could just select all of them by class name). Working fiddle
EDIT
Per the comment, you want to know how many children each row has, that's easy to add as a data attribute (or any other custom attribute) and then access it after this function has run.
I am trying to remove the following div from a page with my chrome extension
HTML (TO REMOVE)
<div class="base-popup js-base-popup"><div class="js-obscurity base-popup__obscurity"></div>
<div class="base-popup__indent"></div>
<div class="base-popup__wrap">
<div class="base-popup__container clearfix base-popup__container -decor" style="width:500px;">
<i class="s-icon -m -close base-popup__close js-close"></i>
<div class="base-popup__content js-content"><div><div class="s-text">Sample Text.
<!-- close tag -->
</p>
<!-- close tag in translate -->
</div></div></div>
</div>
Here is the JS in my content script
function removeElementsByClassName(names) {
var els = document.getElementsByClassName(names),
i, element;
for (i = els.count - 1; i > 0; i -= 1) {
element = els[i];
element.parentElement.removeChild(element);
}
}
removeElementsByClassName('base-popup js-base-popup');
getElementsByClassName only accepts a single class name, but you're giving it two. Since the HTML you've shown only has a single element that has either of the two classes you're using, if that's the only element you want to remove, just pick one:
removeElementsByClassName("base-popup");
// or
removeElementsByClassName("js-base-popup");
Alternately, you could use querySelectorAll with a CSS selector:
function removeElementsBySelector(selector) {
var els = document.querySelectorAll(selector),
i, element;
for (i = els.count - 1; i > 0; i -= 1) {
element = els[i];
element.parentElement.removeChild(element);
}
}
Then if you want to remove elements that have either class:
removeElementsBySelector('.base-popup, .js-base-popup');
Or if you only want to remove a single element that has both classes:
removeElementsBySelector('.base-popup.js-base-popup');
And as this is a Chrome extension, you can do that rather more simply with Array.from, forEach, and Element#remove:
function removeElementsBySelector(selector) {
Array.from(document.querySelectorAll(selector)).forEach(element => {
element.remove();
});
}
your javascript is completely wrong. the right way:
function removeElementsByClassName(names){
names=names.split(" ");//you just get elems by one class so you need to split it into multiple operations
for(var a=1;a<names.length;a++){//ability to remove multiple classes
removeElementsByClassName(names[a]);
}
var els = document.getElementsByClassName(names[0]);
for (var i =0; i<els.length ; i++) { // its length not count
var element = els[i];
element.parentElement.removeChild(element);
}
}
removeElementsByClassName('base-popup js-base-popup');
this removes all elements that contain one of these classes, if you wanted sth else see the other solution.
I have some div ids that are generated dynamicly via php
<div id='a<?php echo $gid?>>
How can I access them in JavaScript? All these divs start with "A" followed by a number.
Is there some kind of search function
getElementById(a*)?
Thanks for any help
No generic JavaScript function for this (at least not something cross browser), but you can use the .getElementsByTagName and iterate the result:
var arrDivs = document.getElementsByTagName("div");
for (var i = 0; i < arrDivs.length; i++) {
var oDiv = arrDivs[i];
if (oDiv.id && oDiv.id.substr(0, 1) == "a") {
//found a matching div!
}
}
This is the most low level you can get so you won't have to worry about old browsers, new browsers or future browsers.
To wrap this into a neater function, you can have:
function GetElementsStartingWith(tagName, subString) {
var elements = document.getElementsByTagName(tagName);
var result = [];
for (var i = 0; i < elements.length; i++) {
var element = elements[i];
if (element.id && element.id.substr(0, subString.length) == subString) {
result.push(element);
}
}
return result;
}
The usage example would be:
window.onload = function() {
var arrDivs = GetElementsStartingWith("div", "a");
for (var i = 0; i < arrDivs.length; i++) {
arrDivs[i].style.backgroundColor = "red";
}
};
Live test case.
In case you choose to use jQuery at some point (not worth for this thing alone) all the above code turns to single line:
$(document).ready(function() {
$('div[id^="a"]').css("background-color", "blue");
});
Updated fiddle, with jQuery.
No, you need a fixed id value for getElementById to work. However, there are other ways to search the DOM for elements (e.g. by CSS classes).
You can use querySelectorAll to get all divs that have an ID starting with a. Then check each one to see if it contains a number.
var aDivs = document.querySelectorAll('div[id^="a"]');
for(var index = 0, len = aDivs.length; index < len; index++){
var aDiv = aDivs[index];
if(aDiv.id.match(/a\d+/)){
// aDiv is a matching div
}
}
DEMO: http://jsfiddle.net/NTICompass/VaTMe/2/
Well, I question myself why you would need to select/get an element, that has a random ID. I would assume, you want to do something with every div that has a random ID (like arranging or resizing them).
In that case -> give your elements a class like "myGeneratedDivs" with the random ID (if you need it for something).
And then select all with javascript
var filteredResults=document.querySelectorAll(".myGeneratedDivs").filter(function(elem){
....
return true;
});
or use jQuery/Zepto/YourWeaponOfChoice
var filteredResults=$(".myGeneratedDivs").filter(function(index){
var elem=this;
....
return true;
});
If you plan to use jQuery, you can use following jQuery selectors
div[id^="a"]
or
$('div[id^="id"]').each(function(){
// your stuff here
});
You will have to target the parent div and when someone click on child div inside a parent div then you can catch the child div.
<div id="target">
<div id="tag1" >tag1</div>
<div id="tag1" >tag2</div>
<div id="tag1" >tag3</div>
</div>
$("#target").on("click", "div", function() {
var showid = $(this).attr('id');
alert(showid)
});
getElementById() will return the exact element specified. There are many javascript frameworks including jQuery that allow much more powerful selection capabilities. eg:
Select an element by id: $("#theId")
Select a group of elements by class: $(".class")
Select subelements: $("ul a.action")
For your specific problem you could easily construct the appropriate selector.
This sounds a little crazy, but I'm wondering whether possible to get reference to comment element so that I can dynamically replace it other content with JavaScript.
<html>
<head>
</head>
<body>
<div id="header"></div>
<div id="content"></div>
<!-- sidebar place holder: some id-->
</body>
</html>
In above page, can I get reference to the comment block and replace it with some content in local storage?
I know that I can have a div place holder. Just wondering whether it applies to comment block.
Thanks.
var findComments = function(el) {
var arr = [];
for(var i = 0; i < el.childNodes.length; i++) {
var node = el.childNodes[i];
if(node.nodeType === 8) {
arr.push(node);
} else {
arr.push.apply(arr, findComments(node));
}
}
return arr;
};
var commentNodes = findComments(document);
// whatever you were going to do with the comment...
console.log(commentNodes[0].nodeValue);
It seems there are legitimate (performance) concerns about using comments as placeholders - for one, there's no CSS selector that can match comment nodes, so you won't be able to query them with e.g. document.querySelectorAll(), which makes it both complex and slow to locate comment elements.
My question then was, is there another element I can place inline, that doesn't have any visible side-effects? I've seen some people using the <meta> tag, but I looked into that, and using that in <body> isn't valid markup.
So I settled on the <script> tag.
Use a custom type attribute, so it won't actually get executed as a script, and use data-attributes for any initialization data required by the script that's going to initialize your placeholders.
For example:
<script type="placeholder/foo" data-stuff="whatevs"></script>
Then simply query those tags - e.g.:
document.querySelectorAll('script[type="placeholder/foo"]')
Then replace them as needed - here's a plain DOM example.
Note that placeholder in this example isn't any defined "real" thing - you should replace that with e.g. vendor-name to make sure your type doesn't collide with anything "real".
Building off of hyperslug's answer, you can make it go faster by using a stack instead of function recursion. As shown in this jsPerf, function recursion is 42% slower on my Chrome 36 on Windows and 71% with IE11 in IE8 compatibility mode. It appears to run about 20% slower in IE11 in edge mode but faster in all other cases tested.
function getComments(context) {
var foundComments = [];
var elementPath = [context];
while (elementPath.length > 0) {
var el = elementPath.pop();
for (var i = 0; i < el.childNodes.length; i++) {
var node = el.childNodes[i];
if (node.nodeType === Node.COMMENT_NODE) {
foundComments.push(node);
} else {
elementPath.push(node);
}
}
}
return foundComments;
}
Or as done in TypeScript:
public static getComments(context: any): Comment[] {
const foundComments = [];
const elementPath = [context];
while (elementPath.length > 0) {
const el = elementPath.pop();
for (let i = 0; i < el.childNodes.length; i++) {
const node = el.childNodes[i];
if (node.nodeType === Node.COMMENT_NODE) {
foundComments.push(node);
} else {
elementPath.push(node);
}
}
}
return foundComments;
}
There is an API for document nodes traversal: Document#createNodeIterator():
var nodeIterator = document.createNodeIterator(
document.body,
NodeFilter.SHOW_COMMENT
);
// Replace all comment nodes with a div
while(nodeIterator.nextNode()){
var commentNode = nodeIterator.referenceNode;
var id = (commentNode.textContent.split(":")[1] || "").trim();
var div = document.createElement("div");
div.id = id;
commentNode.parentNode.replaceChild(div, commentNode);
}
#header,
#content,
#some_id{
margin: 1em 0;
padding: 0.2em;
border: 2px grey solid;
}
#header::after,
#content::after,
#some_id::after{
content: "DIV with ID=" attr(id);
}
<html>
<head>
</head>
<body>
<div id="header"></div>
<div id="content"></div>
<!-- sidebar placeholder: some_id -->
</body>
</html>
Edit: use a NodeIterator instead of a TreeWalker
If you use jQuery, you can do the following to get all comment nodes
comments = $('*').contents().filter(function(){ return this.nodeType===8; })
If you only want the comments nodes of the body, use
comments = $('body').find('*').contents().filter(function(){
return this.nodeType===8;
})
If you want the comment strings as an array you can then use map:
comment_strings = comments.map(function(){return this.nodeValue;})
Using document.evaluate and xPath:
function getAllComments(node) {
const xPath = "//comment()",
result = [];
let query = document.evaluate(xPath, node, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
for (let i = 0, length = query.snapshotLength; i < length; ++i) {
result.push(query.snapshotItem(i));
}
return result;
}
getAllComments(document.documentElement);
from my testing, using xPath is faster than treeWalker:
https://jsben.ch/Feagf
This is an old question, but here's my two cents on DOM "placeholders"
IMO a comment element is perfect for the job (valid html, not visible, and not misleading in any way).
However, traversing the dom looking for comments is not necessary if you build your code the other way around.
I would suggest using the following method:
Mark the places you want to "control" with markup of your choice (e.g a div element with a specific class)
<div class="placeholder"></div>
<div class="placeholder"></div>
<div class="placeholder"></div>
<div class="placeholder"></div>
<div class="placeholder"></div>
Find the placeholders the usual way (querySelector/classSelector etc)
var placeholders = document.querySelectorAll('placeholder');
Replace them with comments and keep reference of those comments:
var refArray = [];
[...placeholders].forEach(function(placeholder){
var comment = document.createComment('this is a placeholder');
refArray.push( placeholder.parentNode.replaceChild(comment, placeholder) );
});
at this stage your rendered markup should look like this:
<!-- this is a placeholder -->
<!-- this is a placeholder -->
<!-- this is a placeholder -->
<!-- this is a placeholder -->
<!-- this is a placeholder -->
Now you can access each of those comments directly with your built refArray and do whatevere it is you wanna do... for example:
replace the second comment with a headline
let headline = document.createElement('h1');
headline.innerText = "I am a headline!";
refArray[1].parentNode.replaceChild(headline,refArray[1]);
If you just want to get an array of all comments from a document or part of a document, then this is the most efficient way I've found to do that in modern JavaScript.
function getComments (root) {
var treeWalker = document.createTreeWalker(
root,
NodeFilter.SHOW_COMMENT,
{
"acceptNode": function acceptNode (node) {
return NodeFilter.FILTER_ACCEPT;
}
}
);
// skip the first node which is the node specified in the `root`
var currentNode = treeWalker.nextNode();
var nodeList = [];
while (currentNode) {
nodeList.push(currentNode);
currentNode = treeWalker.nextNode();
}
return nodeList;
}
I am getting over 50,000 operations per second in Chrome 80 and the stack and recursion methods both get less than 5,000 operations per second in Chrome 80. I had tens of thousands of complex documents to process in node.js and this worked the best for me.
https://jsperf.com/getcomments/6
I have a div element in an HTML document.
I would like to extract all elements inside this div with id attributes starting with a known string (e.g. "q17_").
How can I achieve this using JavaScript ?
If needed, for simplicity, I can assume that all elements inside the div are of type input or select.
var matches = [];
var searchEles = document.getElementById("myDiv").children;
for(var i = 0; i < searchEles.length; i++) {
if(searchEles[i].tagName == 'SELECT' || searchEles.tagName == 'INPUT') {
if(searchEles[i].id.indexOf('q1_') == 0) {
matches.push(searchEles[i]);
}
}
}
Once again, I strongly suggest jQuery for such tasks:
$("#myDiv :input").hide(); // :input matches all input elements, including selects
Option 1: Likely fastest (but not supported by some browsers if used on Document or SVGElement) :
var elements = document.getElementById('parentContainer').children;
Option 2: Likely slowest :
var elements = document.getElementById('parentContainer').getElementsByTagName('*');
Option 3: Requires change to code (wrap a form instead of a div around it) :
// Since what you're doing looks like it should be in a form...
var elements = document.forms['parentContainer'].elements;
var matches = [];
for (var i = 0; i < elements.length; i++)
if (elements[i].value.indexOf('q17_') == 0)
matches.push(elements[i]);
With modern browsers, this is easy without jQuery:
document.getElementById('yourParentDiv').querySelectorAll('[id^="q17_"]');
The querySelectorAll takes a selector (as per CSS selectors) and uses it to search children of the 'yourParentDiv' element recursively. The selector uses ^= which means "starts with".
Note that all browsers released since June 2009 support this.
Presuming every new branch in your tree is a div, I have implemented this solution with 2 functions:
function fillArray(vector1,vector2){
for (var i = 0; i < vector1.length; i++){
if (vector1[i].id.indexOf('q17_') == 0)
vector2.push(vector1[i]);
if(vector1[i].tagName == 'DIV')
fillArray (document.getElementById(vector1[i].id).children,vector2);
}
}
function selectAllElementsInsideDiv(divId){
var matches = new Array();
var searchEles = document.getElementById(divId).children;
fillArray(searchEles,matches);
return matches;
}
Now presuming your div's id is 'myDiv', all you have to do is create an array element and set its value to the function's return:
var ElementsInsideMyDiv = new Array();
ElementsInsideMyDiv = selectAllElementsInsideDiv('myDiv')
I have tested it and it worked for me. I hope it helps you.
var $list = $('#divname input[id^="q17_"]'); // get all input controls with id q17_
// once you have $list you can do whatever you want
var ControlCnt = $list.length;
// Now loop through list of controls
$list.each( function() {
var id = $(this).prop("id"); // get id
var cbx = '';
if ($(this).is(':checkbox') || $(this).is(':radio')) {
// Need to see if this control is checked
}
else {
// Nope, not a checked control - so do something else
}
});
i have tested a sample and i would like to share this sample and i am sure it's quite help full.
I have done all thing in body, first creating an structure there on click of button you will call a
function selectallelement(); on mouse click which will pass the id of that div about which you want to know the childrens.
I have given alerts here on different level so u can test where r u now in the coding .
<body>
<h1>javascript to count the number of children of given child</h1>
<div id="count">
<span>a</span>
<span>s</span>
<span>d</span>
<span>ff</span>
<div>fsds</div>
<p>fffff</p>
</div>
<button type="button" onclick="selectallelement('count')">click</button>
<p>total element no.</p>
<p id="sho">here</p>
<script>
function selectallelement(divid)
{
alert(divid);
var ele = document.getElementById(divid).children;
var match = new Array();
var i = fillArray(ele,match);
alert(i);
document.getElementById('sho').innerHTML = i;
}
function fillArray(e1,a1)
{
alert("we are here");
for(var i =0;i<e1.length;i++)
{
if(e1[i].id.indexOf('count') == 0)
a1.push(e1[i]);
}
return i;
}
</script>
</body>
USE THIS I AM SURE U WILL GET YOUR ANSWER ...THANKS