When I click on All, I want to get all the li elements in different rows of table. Here I get all the li elements of one row.
<ul class="clsInfo">
<li id="liAll" onclick="Activelink(this);">
<a href="#">
<label id="lblAll">All</label>
</a>
</li>
</ul>
Code:
function Activelink(sender) {
var a_elements = sender.parentNode.getElementsByTagName("a");
for (var i = 0, len = a_elements.length; i < len; i++) {
a_elements[i].style.color = 'black';
}
}
You describe li elements and tables, but your code is setting the properties of a (anchor) tags. If your "All" link is nested in a table that we can't see in the html sample, then you need to find it with a loop:
function findParentalTable(el) {
var current = el;
while((current !== document) && (current.tagName != "TABLE")) {
current = current.parentNode;
}
return current;
}
Then your code would be
function Activelink(sender) {
var parentalTable = findParentalTable(sender);
var a_elements = parentalTable.getElementsByTagName("a");
for (var i = 0, len = a_elements.length; i < len; i++) {
a_elements[i].style.color = 'black';
}
}
The parent node of an element is another DOM element, and all DOM elements have the property tagName, which is the uppercase tag string, like TABLE. The while loop is just walking up the DOM tree looking for a <table> tag. As soon as it finds a table tag, the current.tagName will be TABLE and the condition will fail, permitting the function to return the element. Just in case there is no table element above the element passed to findParentalTable, I also check that we haven't reached the top of the DOM, the document node; !== checks for an exact reference match (generally good practice to use !== and ===).
Related
I'm trying to build a code that will search through an entire page for a specific word and if it finds this word, it is supposed to change the dom of the found element.
With my current code I'm able to find the element but when I change the innerHTML, it is changing all the page content.
How can I only change the innerHTML of the elements with the word JavaScript?
var nodes = document.querySelectorAll('*');
for (var i = 0; i < nodes.length; i++) {
if(nodes[i].innerHTML.indexOf('JavaScript') !== -1) {
console.log(typeof nodes[i]);
nodes[i].innerHTML = 'text changed';
}
}
I know that the problem is because I'm targetting all the nodes, and for this reason, it is changing all the HTML. How can I prevent that and only change elements that matches JavaScript?
hi when you use nodes[i].innerHTML.indexOf('JavaScript') this your <body> and <html> has this word in innerHTML then change your document but i add new condition to if like this nodes[i].innerHTML.indexOf('<') == -1 that say only in child node find this string and in parent node don't check
var nodes = document.querySelectorAll('*');
for (var i = 0; i < nodes.length; i++) {
console.log(nodes[i].innerHTML.indexOf('<'))
if(nodes[i].innerHTML.indexOf('JavaScript') != -1 && nodes[i].innerHTML.indexOf('<') == -1 ) {
console.log(typeof nodes[i]);
nodes[i].innerHTML = 'text changed';
}
}
<div>
<p>hello <span>JavaScript</span></p>
<h1>hello World!</h1>
</div>
How can this jQuery-dependent code
$('.myElement').click(function () {
drawMode = !drawMode;
$icon = $(this).children('i');
if (drawMode) {
$icon.removeClass('a').addClass('b');
} else {
$icon.removeClass('b').addClass('a');
}
});
be rewritten into native javascript?
I have tried
var element = document.getElementsByClassName('myElement')[0];
element.addEventListener('click', function (e) {
drawMode = !drawMode;
var icon = this.children()[0];
if (drawMode) {
icon.classList.remove('a').add('b');
} else {
icon.classList.remove('b').add('a');
}
});
but I cannot find the children element correctly.
jQuery's children allows you to filter by selector, something that isn't in the DOM API (you can find all descendants matching a given CSS selector, but you can't [for now] limit it to just children).
If it doesn't matter whether it's a child or just any descendant, then:
var icon = this.querySelector("i");
That finds the first descendant within the element that's an i element. I suspect that would work just fine for you. The only time it might not would be if you had this:
<div class="myElement">
<span>
<i>You DON'T want this one</i>
</span>
<i>You do want this one</i>
</div>
If that's the case and you need to only look at children, not all descendants, you'll need a loop:
var icon = null;
var n;
for (n = 0; n < !icon && this.children.length; ++n) {
if (this.children[n].tagName.toLowerCase() === "i") {
icon = this.children[n];
}
}
In ES2015+ (you can transpile to use it today), that's so much tidier:
let icon = Array.from(this.children)
.find(child => child.tagName.toLowerCase() === "i");
A few notes:
The add and remove functions of the classList do not return the classList object, so you can't concatenate them (e.add().remove(), like you are used to do in jQuery).
In your code you only go over the first element, while when using jQuery the changes are made for all elements that you selected.
I used the querySelectorAll and filtered out elements that are not direct childs, (checked for the parentElement since you used the children() function of jQuery).
Here is an example:
drawMode = true;
var elements = document.getElementsByClassName('myElement');
for (var i = 0; i < elements.length; i++) {
elements[i].addEventListener('click', function() {
var that = this;
drawMode = !drawMode;
var icons = this.querySelectorAll('i');
for (var j = 0; j < icons.length; j++) {
var icon = icons[j];
if (icon.parentElement != that) {
continue;
}
if (drawMode) {
icon.classList.remove('a');
icon.classList.add('b');
} else {
icon.classList.remove('b')
icon.classList.add('a');
}
}
});
}
i.a {
background: red;
}
i.b {
background: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="myElement">
<i>asd</i><br />
<i>fgh</i><br />
<span><i>This element will not change because he isn't a direct child</i></span><br />
</div>
Generally, document.querySelectorAll is very useful when converting jQuery to vanilla javascript.
Returns a list of the elements within the document (using depth-first pre-order traversal of the document's nodes) that match the specified group of selectors. The object returned is a NodeList.
// get a NodeList of elements which match CSS Selector '.myElement'
var elements = document.querySelectorAll('.myElement');
for (var i = 0; i < elements.length; i++ ) {
// loop through every element with class 'myElement'
var element = elements[i];
element.addEventListener('click', function(event) {
drawMode = !drawMode;
var icon = element.querySelector('i');
if (drawMode) {
icon.classList.remove('a');
icon.classList.add('b');
} else {
icon.classList.remove('b');
icon.classList.add('a');
}
});
}
Note I've also used element.querySelector to match descendants of the currently processed element.
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/
Hi i am trying to change Display property of any HTML Tag with certain attribute..
But after many tries i am unable to change the tag properties.. My code is as below
function getAllElementsWithAttribute(attribute)
{
var matchingElements = [];
var allElements = document.getElementsByTagName('*');
for (var i = 0; i < allElements.length; i++)
{
if (allElements[i].getAttribute(attribute))
{
// Element exists with attribute. Add to array.
matchingElements.push(allElements[i]);
}
}
return matchingElements;
}
tags = getAllElementsWithAttribute('data-shares');
for(i=0;i<tags.length;i++)
{
tags[i].style.display = "none";
}
And the HTML has below Tag
<div class="shareTools" data-shares="facebook" data-url="#" data-title="Facebook" data-description="Facebook">
<div class="shareToolsBox">
<ul class="shareToolsList">
<li data-share="facebook">
<span>Facebook</span>
</li>
</ul>
</div>
</div>
Does anyone has any idea how to change Tag Style of any tag which has attribut i-e data-shares...
Change the function call to:
tags = getAllElementsWithAttribute('data-shares');
Here's it working on a JS Bin demo: http://jsbin.com/ufogExo/1/ The <div>s with the data-shares attribute are all hidden.
The problem was indeed the extra commas you had on your function call arguments.
I believe this does what you want:
function getAllElementsWithAttribute(attribute)
{
var items = document.querySelectorAll('['+attribute+']'),
i = items.length;
while ( i-- > 0 && (items[i].style.display = 'none') );
}
getAllElementsWithAttribute('data-shares');
see
http://jsfiddle.net/754zR/
If I wanted to hide all elements except for those within a <div id="content"> (including div#content itself), I could use the following CSS:
*
{
visibility: hidden !important;
}
div#content, div#content *
{
visibility: visible !important;
}
One thing to note about this solution is that the hidden elements still take up space. Unfortunately, not all elements have the same display attribute, so you cannot simple simply replace visibility above with display.
Using JavaScript, how can I set all elements to that are not within the <div id="#content"> 'family' to display: none?
A general purpose solution to change the style on the fewest objects, but make sure that #content and all it's sub-elements are visible requires an algorithm to traverse up from #content and hide all siblings at each level up without ever hiding an ancestor of #content. Because this starts at #content and goes up, it never hides any elements inside of #content.
function hideAllExcept(id) {
var el = document.getElementById(id);
while (el && el != document.body) {
// go one level up
var parent = el.parentNode;
// get siblings of our ancesotr
var siblings = parent.childNodes;
// loop through the siblings of our ancestor, but skip out actual ancestor
for (var i = 0, len = siblings.length; i < len; i++) {
if (siblings[i] != el && siblings[i].nodeType == 1) {
// only operate on element nodes
siblings[i].style.display = "none";
}
}
el = parent;
}
}
hideAllExcept("content");
Caveat: this first version does not hide text nodes that are siblings of an ancestor of #content (all other text nodes outside of #content are hidden because their parent is hidden). To hide those text nodes too, they would have to get wrapped in a <span> tag so the style could be set on the <span> tag, but I don't know if the OP needs that level of complexity or wants the text nodes wrapped in that way.
For completeness, here's a version that will wrap parent sibling text nodes so they can also be set to display: none. This may or may not be needed depending upon the source HTML:
function hideAllExcept(id) {
var el = document.getElementById(id);
while (el && el != document.body) {
// go one level up
var parent = el.parentNode;
// get siblings of our ancesotr
var siblings = parent.childNodes;
// loop through the siblings of our ancestor, but skip out actual ancestor
for (var i = 0, len = siblings.length; i < len; i++) {
var node = siblings[i];
if (node != el) {
if (node.nodeType == 1) {
// only operate on element nodes
node.style.display = "none";
} else if (node.nodeType == 3) {
// wrap text node in span object so we can hide it
var span = document.createElement("span");
span.style.display = "none";
span.className = "xwrap";
node.parentNode.insertBefore(span, node);
// Be wary of the dynamic siblings nodeList changing
// when we add nodes.
// It actually works here because we add one
// and remove one so the nodeList stays constant.
span.appendChild(node);
}
}
}
el = parent;
}
}
hideAllExcept("content");
And a working demo: http://jsfiddle.net/jfriend00/yVWDx/
Try this
var al = document.body.getElementsByTagName("*");
for(var i =0;i<al.length;i++)
{
var elm = al[i];
if(elm.parentNode.id != 'content') {
elm.style.display = 'none';
}
}