Can somebody explain me what did I do wrong?
let toolbarForChilds = document.getElementById("toolbar");
for (let i = 0; i < toolbarForChilds.childNodes.length; i++) {
toolbarForChilds.childNodes[i].style.cursor = "default";
}
<div class="sample-toolbar" id="toolbar" style="text-align: center;">
<div id="title">#1</div>
<div id="another thing">#2</div>
</div>
I get this error in the console:
Uncaught TypeError: Cannot set property 'cursor' of undefined
Node.childNodes
childNodes includes all child nodes—including non-element nodes like text and comment nodes. To get a collection of only elements, use ParentNode.children instead.
You do not need to use childNodes. You can target all the elements with querySelectorAll() and loop through them like the following way:
let toolbarForChilds = document.querySelectorAll("#toolbar div");
for (let i = 0; i < toolbarForChilds.length; i++) {
toolbarForChilds[i].style.cursor = "default";
}
<div class="sample-toolbar" id="toolbar" style ="text-align: center;">
<div id ="title">#1</div>
<div id ="another thing">#2</div>
</div>
The problem here is that childNodes not only returns elements. There are also nodes without a style attribute. As example between the html tags there are empty text nodes. You should see this in your browsers console if you add console.log(toolbarForChilds.childNodes[i]); inside the for loop.
The reason your code doesn't work is that childNodes also includes the newlines between the elements. You can console.log the childNodes to see them. Your code will work if you wrap it in a try-catch to skip those, although you should follow Mamun's answer for a cleaner way to do it.
for (let i = 0; i < toolbarForChilds.childNodes.length; i++) {
try {
toolbarForChilds.childNodes[i].style.cursor = "default";
}
catch {
continue;
}
}
node.childNodes returns elements without style attributes like text nodes. For only getting node elements, that is, div's: id ="title" & id ="another thing" use node.children. This is implemented below.
let toolbarForChilds= document.getElementById("toolbar");
/* console.log(toolbarForChilds.childNodes); */
for (let i = 0; i < toolbarForChilds.children.length; i++) {
toolbarForChilds.children[i].style.cursor = "help";
}
<div class="sample-toolbar" id="toolbar" style ="text-align: center;">
<div id ="title">#1</div>
<div id ="another thing">#2</div>
</div>
Related
HTML
<div id="divID">
<label></label>
<textarea></textarea>
</div>
JavaScript
function invisible(){
let div = document.getElementById("divID");
let children = div.childNodes;
for (let i = 0; i < children.length; i++) {
children[i].style.display = "none";
}
}
After calling the function nothing happens. What I'm doing wrong?
You have to set divID to your div tag.
<div id="divID">
<label></label>
<textarea></textarea>
</div>
And then you have to use div.children in invisible function.
function invisible(){
let div = document.getElementById("divID");
let children = div.children;
for (let i = 0; i < children.length; i++) {
children[i].style.display = "none";
}
}
<input type="button" onClick=" invisible()" value="Remove" />
<div id="divID">
<label></label>
<textarea></textarea>
</div>
You can make the function more reusable by accepting the element whose children are to be hidden as the first argument. It currently only works for the element with id of "divID".
function invisible(parent){
for(const child of parent.children) child.style.display = 'none';
}
invisible(document.querySelector('div'))
<div>
<label>Label</label>
<textarea>Textarea</textarea>
</div>
The problem seems to be your use of childNodes instead of children as other answers have pointed out.
This answer attempts to give some more context on what is happening in addition to the other answers.
let div = document.getElementById("divID");
console.log(div.childNodes)
// Returns something like
NodeList(5) [text, label, text, textarea, text]
console.log(div.children)
// Returns something like
HTMLCollection(2) [label, textarea]
So childNodes returns a NodeList and children returns an HTMLCollection.
The definition children on mdn explains the difference between children and childNodes:
Element.children includes only element nodes. To get all child nodes, including non-element nodes like text and comment nodes, use Node.childNodes.
The problem is that these text nodes don't have a style property. So it returns undefined. Trying to access the display property on style then causes a TypeError. Since the first element is a text element the loop fails immediately and the label and textarea are never hidden.
use children instead of childNodes:
function invisible(){
let div = document.getElementById("divID");
let children = div.children; //<== children instead of childNodes
for (let i = 0; i < children.length; i++) {
children[i].style.display = "none";
}
}
//just to test after 1.5 sec all children of divID will be removed(display=none)
setTimeout(invisible, 1500)
<div id='divID'>
<label>test1</label>
<textarea>test2</textarea>
</div>
I've got following HTML:
<span class="testClass1" >
wanted Text
<a class="ctx" href="#"></a>
</span>
Now I want to get the text "wanted Text".
How can I achieve this?
I tried with:
document.getElementsByClassName("testClass1");
I also tried with document.getElementsByTagName() but I don't know how to use them properly.
You can use querySelectorAll
hence:
document.querySelectorAll('.testclass1 a')
will return all the <a> items children of a .testclass1
Snippet example:
var elements = document.querySelectorAll('.testClass1 a')
console.log(elements) // open the console to see this
console.log(elements[0].text) // this gets the first <a> text `wanted Text`
<span class="testClass1" >
wanted Text
<a class="ctx" href="#"></a>
</span>
The getElementsByClassName() function returns an array of matching elements, so if you need to access them, you could do so using a loop :
// Get each of the elements that have the class "testClass1"
var elements = document.getElementsByClassName("testClass1");
// Iterate through each element that was found
for(var e = 0; e < elements.length; e++){
// Get the inner content via the innerHTML property
var content = elements[e].innerHTML;
}
If you need to actually access the <a> tags directly below some of the elements as your edit indicates, then you could potentially search for those wihtin each of your existing elements using the getElementsbyTagName() function :
// Get each of the elements that have the class "testClass1"
var elements = document.getElementsByClassName("testClass1");
// Iterate through each element that was found
for(var e = 0; e < elements.length; e++){
// Find the <a> elements below this element
var aElements = elements[e].getElementsByTagName('a');
// Iterate through them
for(var a = 0; a < aElements.length; a++){
// Access your element content through aElements[a].innerHTML here
}
}
You can also use an approach like squint's comment or Fred's which take advantage of the querySelectorAll() function as the getElementsByClassName() and getElementsByTagName() are better served when accessing multiple elements instead of one specifically.
Try this:
document.getElementsByClassName("testClass1")[0].getElementsByTagName('a')[0].innerText
var testClass1 = document.getElementsByClassName("testClass1");
console.log(testClass1[0].innerHTML);
Please Note: I am looking for a Javascript only solution, jQuery will not help as I can't use it with the given application I am working within.
I have the following HTML in my DOM:
<div class="mktoFormRow">
<div class="mktoFieldDescriptor mktoFormCol" style="margin-bottom: 10px;">
<div class="mktoOffset" style="width: 10px;"></div>
<div class="mktoFieldWrap">
<label for="Agency__c" class="mktoLabel mktoHasWidth" style="width: 100px;">
<div class="mktoAsterix">*</div>Agency:</label>
<div class="mktoGutter mktoHasWidth" style="width: 10px;"></div>
<div class="mktoLogicalField mktoCheckboxList mktoHasWidth" style="width: 150px;">
<input name="Agency__c" id="Agency__c" type="checkbox" value="yes" class="mktoField">
<label for="Agency__c"></label>
</div>
<div class="mktoClear"></div>
</div>
<div class="mktoClear"></div>
</div>
<div class="mktoClear"></div>
I want to use Javascript to target the first label (in this example, the one with for="Agency__c") whenever the div with a class of mktoCheckboxList is present.
This is as far as I've been able to figure out in Javascript, but I'm at a loss. My thought process is to target the previous element before mktoCheckboxList by either by element type of label or its class of mktoLabel.
var checkboxes = document.getElementsByClassName('mktoCheckboxList');
var count = checkboxes.length;
for (i = 0; i < count; i++) {
console.log(checkboxes[i].previousElementSibling);
}
This solution needs to be agnostic of an actual name value, as I want this to work whenever a checkbox is presented without knowing what it's properties are, hence the use of the class / elements.
Here's my jsfiddle: http://jsfiddle.net/darcyvoutt/1y9s00k7/
document.querySelector is now supported by all major browsers (see can i use).
document.querySelector(".mktoCheckboxList label")
will select the first label it finds inside .mktoFieldDescriptor.
You can also do it on an element:
parent.querySelector("label");
If you need to check if a div contains a specific element before retrieving another you can do:
querySelectorAll(".mktoFieldDescriptor").filter(function(container){
// Remove the containers that do not contain .mktoCheckboxList.
return !!container.querySelector(".mktoCheckboxList");
}).map(function(container){
// Get the first label.
return container.querySelector("label")
}).forEach(function(label){
// Do your label stuff.
});
One possible solution would be:
var checkboxes = document.getElementsByClassName('mktoCheckboxList');
var count = checkboxes.length;
for (i = 0; i < count; i++) {
console.log(checkboxes[i].parentNode.querySelector('label'));
}
Please note that this solution will work only if you have a single .mktoCheckboxList element in the same div with the label.
Fiddle
Here's one possible approach:
Bind every input with it's label. Then lookup the input you need to work with, and get the label elem by that:
// Scan the page for labels:
var labels = document.getElementsByTagName('LABEL');
// Find the corresponding input:
for (var i = 0; i < labels.length; i++) {
if (labels[i].htmlFor != '') {
// Assign a reference to the label from the actual form element:
var elem = document.getElementById(labels[i].htmlFor);
if (elem)
elem.label = labels[i];
}
}
After that's done, you can easily do:
// Lookup all inputs:
var inputs = document.getElementsByTagName("input");
for (var i = 0, max = inputs.length; i < max; i++){
// Act only on checkboxes:
if (inputs[i].type === 'checkbox')
console.log(inputs[i]); // Look! It's the label!
}
Using this method you use nothing but the tag name input and type checkbox in order to locate your labels.
You could use document.evaluate and address the label you want via XPath. Untested:
//div[contains(#class, 'mktoCheckboxList')]/preceding::label[1]
I need to hide all the elements that have the string "replies-36965584" anywhere in their IDs.
HTML:
<div id="replies-36965584_1">aaaa</div>
<div id="replies-36965584_2">aaaa</div>
<div id="replies-36965584_3">aaaa</div>
<div id="replies-36965584_4">aaaa</div>
<div id="replies-36222224_2">nnnn</div>
JavaScript:
document.getElementById("replies-36965584").style.display="none"
How can I modify this JS to select the first four elements?
You can do this with CSS and attribute selectors.
[att^=val]
Represents an element with the att attribute whose value begins with the prefix "val". If "val" is the empty string then the selector does not represent anything.
Source: http://www.w3.org/TR/css3-selectors/#attribute-substrings
jsfiddle
CSS
[id^="replies-36965584_"] {
display: none;
}
Is using jQuery an option? If so, this is dead simple:
$(document).ready(function(){
$('div[id^="replies-36965584"]').hide();
});
If you're unfamiliar with jQuery, here's a link to get started: http://learn.jquery.com/javascript-101/getting-started/
EDIT: Fixed syntax error.
EDIT: Added jsFiddle: http://jsfiddle.net/xbVp9/
If you don't know certain literal values but you know the general pattern and only the number will change, then I will consider some matching with regular expresiion.
You can do it the painful way:
var o = document.getElementsByTagName("div");
for (var i=0;i<o.length;i++) {
if(o[i].id.indexOf('replies-36965584') == 0) {
o[i].style.display = 'none';
}
}
The only way to do this with vanilla javascript that I know of, is to fetch all the divs on the page, and test the id's for the ones you want.
var divs = document.getElementsByTagName('div');
for (var i = 0; i < divs.length; ++i) {
var div = divs[i];
if (/replies-36965584/.test(div.id)) {
div.style.display = 'none';
}
}
I have multiple div elements with same id='mydiv'.I want to calculate these divs and Iam using the code
document.getElementById('mydiv').length
But it is not working
What you should do is use class instead of ID's. ID is for one element only, class is for multiple.
http://jsfiddle.net/d7AHV/
It won't work as getElementById will always return an element with the specified ID and null if the specified ID doesn't exist
From ECMA
getElementById(elementId) This method returns a Element. The elementId
parameter is of type DOMString.
What you can do is to assign each div with class
<div class="mydiv"></div>
<div class="mydiv"></div>
<div class="mydiv"></div>
<div class="mydiv"></div>
<div class="mydiv"></div>
And iterate over:
var divs = document.getElementsByTagName('div');
var count = 0;
for(var i = 0; i < divs.length; i++) {
if(divs[i].className == 'mydiv') count++;
}
alert(count);
If your clients support document.getElementsByClassName(), it's even more concise:
alert(document.getElementsByClassName('mydiv').length)
You've been told about multiple elements with the same ID, but in rare cases it might be unavoidable (e.g. an XML document over which you have no control). The only adverse behaviour is that selecting by ID will usually only return the first one (but that's not guaranteed).
You can count elements with the same id by looping over all the elements in the document and counting the ones with a matching id, e.g.
function countSameIds(id) {
var allNodes = document.getElementsByTagName('*');
for (var i=allNodes.length, count=0; i; ) {
if (allNodes[--i].id == id) {
++count;
}
}
return count;
}