I am trying to loop over elements with a specific class and attach an ID to them.
var items = document.getElementsByClassName("item");
for(var i = 0; i < items.length; i++)
{
items[i].id = "item_" + i;
}
console.log(items);
If I run that I get the error Cannot set property 'id' of undefined
However the console.log(items) returns me the correct collection of items:
HTMLCollection []
0: div.item
1: div.item
length: 2
__proto__: HTMLCollection
But as soon as I try to get the index console.log(testimonials[0]) it is undefined.
HTML:
<div class="slider">
<div class="item">
Item 1
</div>
</div>
<div class="slider">
<div class="item">
Item 2
</div>
</div>
The issue could be your script is running before the DOM is fully ready.
To solve the issue, you can place your code at the bottom of the body.
OR:
Try wrapping your code with DOMContentLoaded, this will ensure that your code will be executed once the DOM is fully ready.
<script>
document.addEventListener("DOMContentLoaded", function(event) {
var items = document.getElementsByClassName("item");
for(var i = 0; i < items.length; i++)
{
items[i].id = "item_" + i;
}
console.log(items);
});
</script>
<div class="slider">
<div class="item">
Item 1
</div>
</div>
<div class="slider">
<div class="item">
Item 2
</div>
</div>
With vanilla js always do DOM related operations after DOM is ready to use. And also before accessing/working with any DOM element check that it isn't nullable (not equal to null). With these practices you won't see any error with DOM elements because it is the safe way with manipulating with DOM elements. In regular loop always cache array.length. Avoid using anonymous function it is non-future proof and not debug-friendly way. Also write all js in separate js file.
HTML
<div class="slider">
<div class="item">
Item 1
</div>
</div>
<div class="slider">
<div class="item">
Item 2
</div>
</div>
JS
document.addEventListener("DOMContentLoaded", onDomReadyHandler);
function onDomReadyHandler(event) {
var items = document.getElementsByClassName('item');
var itemsLen = items.length;
for(var i = 0; i < itemsLen; i++) {
items[i].id = "item_" + i;
}
console.log(items);
}
Check this code:
<html>
<head>
<script>
window.onload = function(e){
var allItem = document.getElementsByClassName("item");
for(var i = 0; i < allItem.length; i++)
{
document.getElementsByClassName("item")[i].setAttribute("id", "item_" + i);
}
};
</script>
</head>
<body>
<div class="slider">
<div class="item" id="">
Item 1
</div>
</div>
<div class="slider">
<div class="item" id="">
Item 2
</div>
</div>
</body>
</html>
Hope it helps you.
Try using
items[i].setAttribute("id", "item_" + i);
Fore more details you can visit documentation of
https://www.w3schools.com/jsref/met_element_setattribute.asp
https://www.w3schools.com/jsref/met_element_getattribute.asp
Fiddle for it:
https://jsfiddle.net/abdulrauf618/n14v58zs
Related
User can, by pressing a button, select a particular topic of interest. When that happens, various divs will either become visible or invisible depending on whether that div has a link referring to that topic.
function GetPostsByTopic(topic) {
var area = document.getElementById("postArea");
var topicAreas = area.getElementsByClassName("topicArea");
for (i = 0; i < topicAreas.length; i++) {
var children = topicAreas[i].children;
var topics = [];
for (j = 0; j < children.length; j++) {
topics.push(children[j].getAttribute("asp-route-name"));
document.getElementById("firstTest").innerHTML = children[j].toString();
}
var b = topics.includes(topic);
if (b == true) {
var parentId = document.getElementById(topicAreas[i]).parentNode.id;
document.getElementById(parent).style.display = 'block';
} else {
document.getElementById(parent).style.display = 'none';
}
}
}
<div class="topicBox">
<button class="topicButton" onclick="GetPostsByTopic('Pets')">Pets</button>
<button class="topicButton" onclick="GetPostsByTopic('Vacation')">Vacation</button>
</div>
<div id="postArea">
<div class="post" id="post1">
<div class="topicArea">
<a asp-action="Topic" asp-route-name="Pets">Pets</a>
</div>
</div>
<div class="post" id="post2">
<div class="topicArea">
<a asp-action="Topic" asp-route-name="Vacation">Vacation</a>
</div>
</div>
<div class="post" id="post3">
<div class="topicArea">
<a asp-action="Topic" asp-route-name="Pets">Pets</a>
</div>
</div>
</div>
The trouble, as far as I can tell, begin early in the JS part. I can see that when a do var children=topicAreas[i].children, I get nothing.
I hope this is what you're trying to do. Based on what button you click, respective div is displayed.
function GetPostsByTopic(topic) {
var area = document.getElementById("postArea");
var topicAreas = area.getElementsByClassName("topicArea");
for (i = 0; i < topicAreas.length; i++) {
var children = topicAreas[i].children;
for (j = 0; j < children.length; j++) {
var parentId = topicAreas[i].parentNode.id;
if(children[j].getAttribute("asp-route-name") === topic){
document.getElementById(parentId).style.display = 'block';
}else{
document.getElementById(parentId).style.display = 'none';
}
}
}
}
<div class="topicBox">
<button class="topicButton" onclick="GetPostsByTopic('Pets')">Pets</button>
<button class="topicButton" onclick="GetPostsByTopic('Vacation')">Vacation</button>
</div>
<div id="postArea">
<div class="post" id="post1">
<div class="topicArea">
<a asp-action="Topic" asp-route-name="Pets">Pets</a>
</div>
</div>
<div class="post" id="post2">
<div class="topicArea">
<a asp-action="Topic" asp-route-name="Vacation">Vacation</a>
</div>
</div>
<div class="post" id="post3">
<div class="topicArea">
<a asp-action="Topic" asp-route-name="Pets">Pets</a>
</div>
</div>
</div>
Children isn't the issue. When you run your code you get the error "Uncaught TypeError: Cannot set property 'innerHTML' of null". Looking at your code where you are using .innerHTML, we see that you are trying to reference an element that you don't have in this code:
document.getElementById("firstTest")
Now, after adding that, you still have some items that you should change.
asp-action and asp-route-name are invalid HTML. Are you using a
framework that requires this syntax?
Don't use .getElementsByClassName().
Use .querySelectorAll() and Array.forEach() on the result for
easier looping.
Don't use .innerHTML when you aren't working with HTML strings as there are security and performance implications to doing so.
Avoid inline styles when you can. Using them causes duplication of code and code is harder to scale. Instead, use CSS classes and the .classList API.
It's not super clear exactly what is supposed to happen when clicking your buttons, but see the updated code below:
function GetPostsByTopic(topic) {
var area = document.getElementById("postArea");
// Don't use .getElementsByClassName() as it provides a live node list
// and causes quite a performance hit, especially when used in loops.
// Use .querySelectorAll() and then use .forEach() on the collection that
// it returns to iterate over them.
area.querySelectorAll(".topicArea").forEach(function(area){
var topics = [];
// No need for children, here. Again, use .querySelectorAll()
area.querySelectorAll("*").forEach(function(child) {
topics.push(child.getAttribute("asp-route-name"));
document.getElementById("firstTest").textContent = child.getAttribute("asp-route-name");
});
if (topics.indexOf(topic) > -1) {
// Don't use inline styles if you can avoid it.
// Instead use pre-made classes.
area.classList.add("hidden");
}
else {
area.classList.remove("hidden");
}
});
}
/* Use CSS classes when possible instead of inline styles */
.hidden { display:none; }
<div class="topicBox">
<button class="topicButton" onclick="GetPostsByTopic('Pets')">Pets</button>
<button class="topicButton" onclick="GetPostsByTopic('Vacation')">Vacation</button>
</div>
<div id="postArea">
<div class="post" id="post1">
<div class="topicArea">
<a asp-action="Topic" asp-route-name="Pets">Pets</a>
</div>
</div>
<div class="post" id="post2">
<div class="topicArea">
<a asp-action="Topic" asp-route-name="Vacation">Vacation</a>
</div>
</div>
<div class="post" id="post3">
<div class="topicArea">
<a asp-action="Topic" asp-route-name="Pets">Pets</a>
</div>
</div>
</div>
<div id="firstTest"></div>
Get content of all elements with the same class name using javascript.
How can I get all innerHTML-content from elements with the same class? I tried the code described below but it doesn't work I only get the first "Hello" from element but I don't get "World! from the second element" Of course there will be many more elements with the same class, not just two.
function myFunction() {
var child = document.querySelectorAll(".child");
var child, i;
for (i = 0; i < child.length; i++) {
var childall = child[i].innerHTML;
}
document.getElementById("demo").innerHTML = childall;
}
<div class="parent" id="parent">
<div class="child" id="child">Hello</div>
<div class="child" id="child">World!</div>
</div>
<button onclick="myFunction()">click</button>
<div class="demo" id="demo">
Move childall out of the loop, and assign an array to it. Now push all innerHTML values into it. After the loop ends join the array to a string, and assign to demo.
function myFunction() {
var child = document.querySelectorAll(".child");
var child, i;
var childall = [];
for (i = 0; i < child.length; i++) {
childall.push(child[i].innerHTML);
}
document.getElementById("demo").innerHTML = childall.join('<br>');
}
<div class="parent" id="parent">
<div class="child" id="child">Hello</div>
<div class="child" id="child">World!</div>
</div>
<button onclick="myFunction()">click</button>
<div class="demo" id="demo">
Instead of a for loop, you can use Array.from() to get an array of children's innerHTML.
function myFunction() {
const childall = Array.from(document.querySelectorAll(".child"), el => el.innerHTML);
document.getElementById("demo").innerHTML = childall.join('<br>');
}
<div class="parent" id="parent">
<div class="child" id="child">Hello</div>
<div class="child" id="child">World!</div>
</div>
<button onclick="myFunction()">click</button>
<div class="demo" id="demo">
var overrideField = document.querySelectorAll('.form_style_override_field');
overrideField.forEach(function (e) {
e.parentNode.parentNode.remove();
});
I am trying to learn vanilla javascript and trying to remove an element which is pulled by classname.
var overrideField = document.getElementsByClassName('form_style_override_field');
for (var i = 0; i < overrideField.length; i++)
{
var controlGroup = overrideField[i].parentNode.parentNode;
controlGroup.remove();
}
var overrideField = document.getElementsByClassName('form_style_override_field');
for (var i = 0; i < overrideField.length; i++)
{
var controlGroup = overrideField[i].parentNode.parentNode;
controlGroup.remove();
}
<div class="tab-pane active show" id="general">
<div class="control-group">
<div class="control-label">Label 1</div>
<div class="controls">
<span class="form_style_override_field"></span>
Control Group 1
</div>
</div>
<div class="control-group">
<div class="control-label">Label 2</div>
<div class="controls">
<span class="form_style_override_field"></span>
Control Group 2
</div>
</div>
</div>
The overrideField variable sees 2 elements and it will only remove the last one. Can anyone help me figure it out please.
Thanks!
getElementsByClassName returns a live collection, so when you remove an element in your for loop the collection (and length) changes so your loop never gets to the last element. Use querySelectorAll instead to return a static collection and then remove the elements.
For example:
var elems = document.querySelectorAll('.class-to-remove');
elems.forEach(function(elem) {
elem.remove();
});
I've been trying to get my head around this probably very simple problem.
I have dynamically generated links, for example #l1, #l2.. and for each link I have a containing an image img. Divs have IDs corresponding to links, for example #li1, when clicked, should toggle div with id #di1 and so on.
I wrote a test, where I iterate through ID numbers and construct jquery button listeners. Something in the lines of:
a = [1,2,3,4]; // those are link and div IDs
for (k=0;k<3;k++){
$("#"+"li"+a[k]).click(function() {
$("#"+"di"+a[k]).toggle();
});
}
But what this gives me are listeners on all links, which toggle only the last div!
So again: I have links within a tag, which when clicked, should toggle a DIFFERENT div with corresponding ID.
What am I doing wrong here?
Thanks..
By the time click is invoked, value of k is 3(because of k++), just use this context.
Make sure for-loop should have k < 4 condition to iterate 4(0, 1, 2, 3) elements.
var a = [1, 2, 3, 4];
for (k = 0; k < 4; k++) {
$("#li" + a[k]).click(function() {
$(this).toggle();
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div id="li1">li1</div>
<div id="li2">li2</div>
<div id="li3">li3</div>
<div id="li4">li4</div>
Going with your approach:
Use closure, inner function remembers the environment in which it is created!
var a = [1, 2, 3, 4];
for (k = 0; k < 4; k++) {
$("#di" + a[k]).click((function(k) {
return function() {
$("#li" + a[k]).toggle();
}
})(k));
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div id="di1">Div 1</div>
<div id="di2">Div 2</div>
<div id="di3">Div 3</div>
<div id="di4">Div 4</div>
<hr>
<hr>
<div id="li1">Links 1</div>
<div id="li2">Links 2</div>
<div id="li3">Links 3</div>
<div id="li4">Links 4</div>
You can also use forEach() as well for cleaner JS code (IMO):
// link and div IDs
var a = [1,2,3,4];
a.forEach(function (v)
{
$("#li" + v).click(function()
{
$("#di" + v).toggle();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li id="li1">one</li>
<li id="li2">two</li>
<li id="li3">three</li>
<li id="li4">four</li>
</ul>
<div id="di1">
<p>One</p>
</div>
<div id="di2">
<p>Two</p>
</div>
<div id="di3">
<p>Three</p>
</div>
<div id="di4">
<p>Four</p>
</div>
I have a div that generates multiple elements inside it:
<div class="lists">
<?php for($i=0;$i<6;$i++) { ?>
<div class="list history[[$i]]" id="history[[$i]]">
<div class="info">
<div class="picture monophoto">
<div class="text">BO</div>
<div class="img" style="background-image: url();"></div>
</div>
<div class="right">
<div class="lineone">John Smith</div>
<div class="linetwo">Daily Essentials</div>
</div>
</div>
<div class="boxes">
<div class="left">
<div class="box box1"></div>
</div>
<div class="right">
<div class="box box2"></div>
<div class="box box3"></div>
</div>
</div>
<a class="cbutton whiteonblack">VIEW LIST<!--SEE <span class="owner">JOHN'S</span>--></a>
</div>
<?php } ?>
</div>
I am trying to wrap the following div with an anchor tag so it links:
<div class="boxes"> </div>
Using jQuery I am trying to wrap this using jQuery that is part of a loop:
for(var i = 0; i < listLength; i++){
for(var y = 0; y < result.history[i].length; y++){
var history = document.getElementById('history' + i);
history.querySelector('.boxes').wrap('');
}
}
This is not resulting in an anchor tag showing up at all on the DOM. What am I doing wrong and how do I fix it?
Edit: I clarified which div
Edit 2: To clarify, each of the links are actually going to be dynamically generated. I am just using google.com as an example. So effecting all of a specific class wont work.
querySelector returns a NodeList object, wrap() is a jquery function, they won't work together, try this :
for(var i = 0; i < listLength; i++){
for(var y = 0; y < result.history[i].length; y++){
$('#history' + i).find('.boxes').first().wrap('');
}
}
You can do this in a single line by selecting the .list .boxes elements:
$('.lists .boxes').wrap('')
Example fiddle
Note that this will only work if you are using HTML5, otherwise it would be invalid to have a block level element (a div) inside an inline element (the a).