Problem with access to dynamically created elements - javascript

I've asked a similar question before but that was about events related to dynamically created elements. Now I just want to change class lists of dynamically created img tags in a div. Here is what is all about, I want to create a slider that contains three images taken with src and alt attributes taken from a JSON file. Function created all three normally and as I wanted put displayNone class on every img except first. Another function should on every 3 seconds check in a loop all the dynamically created img tags for the one that does not contain displayNone class and to add to that particular img class displayNone and then to get next, or if it is last first, img and to remove his displayNone class. I created var inside function to get an array of these images. Does anybody know what the solution is?
function showSlides(slidesJsonData){ // there is no problem with this function it generates img tags when window is loaded
var writingSlides = "";
for (slide in slidesJsonData){
if(slide==0){
writingSlides += `<img src="${slidesJsonData[slide].src}" alt="${slidesJsonData[slide].alt}"/>`;
}
writingSlides += `<img class="displayNone" src="${slidesJsonData[slide].src}" alt="${slidesJsonData[slide].alt}"/>`;
}
document.querySelector("#slider").innerHTML=writingSlides;
}
function slideShow(){
var images = document.querySelectorAll("#slider img");
images.forEach((img,index) => {
if(index<images.length-1){
if(!img.classList.contains("displayNone")){
img.classList.add("displayNone");
img[index+1].classList.remove("displayNone");
}
}
else {
img.classList.add("displayNone");
document.querySelector("#slider img:first-of-type").classList.remove("displayNone");
}
});
setTimeout("slideShow()",3000);
}
slideShow();
Now error is:
Uncaught TypeError: Cannot read property 'classList' of undefined
at main.js:73
at NodeList.forEach (<anonymous>)
at slideShow (main.js:69)
at <anonymous>:1:1

try updating your sliderImages variable before accessing it because it probably is being created before content as finished loading

You are using a for in loop that exposes other enumerable properties of the element collection unrelated to element indexing. Element collections are not proper arrays but rather are array-like objects
When you try to pass these properties to sliderImages[sliderImage] inside your loop they do not return an element with a classList property and no sub property contains which throws the error.
Use a for loop based on length or a for of loop or sliderImages.forEach(callback)
Simple property output example of the for in
const li = document.querySelectorAll('li')
for (let x in li) {
if (isNaN(x)) {
console.log(`Property "${x}" is not an element index`)
} else {
console.log(`Key "${x}" is an element index`)
}
}
<ul>
<li></li>
<li></li>
</ul>

Try this
var images = document.querySelectorAll("#slider img");
let cnt= 0
function slideShow(){
images[cnt].classList.toggle("displayNone")
cnt++
if (cnt>= images.length) cnt = 0;
images[cnt].classList.toggle("displayNone")
}
setInterval(slideShow,3000);

Related

Why can't I remove this class with javascript?

I'm trying to make a skeleton loading screen by having a class 'skeleton' on the elements which styles them then removing it with javascript after a timeout. The issue is that i can't get the javascript to work.
Here's my javascript to remove the class, why isn't it working?
const timeout = setTimeout(loading, 3000);
function loading() {
const element = document.getElementById("skeleton");
element.classList.remove("skeleton");
}
What I think is happening is that you have too many "skeleton" elements with the same id, and ids have to be unique. So remove the ids, and target the classes instead, and use forEach to iterate over each of them to remove the class.
const timeout = setTimeout(loading, 3000);
function loading() {
const skeletons = document.querySelectorAll('.skeleton');
skeletons.forEach(skeleton => {
skeleton.classList.remove('skeleton');
});
}
.skeleton { color: red; }
<div class="skeleton">One</div>
<div class="skeleton">Two</div>
<div class="skeleton">Three</div>
<div class="skeleton">Four</div>
You are calling getElmentById on Class. Can You Share The HTML Elment whose id or class is skeleton
try this
function loading() {
const element = document.getElementsByClassName("skeleton")[0];
element.classList.remove("skeleton");
}
I think the reason behind its not working is that your trying to remove the skeleton class from the skeleton itself. Try targeting the parent Element of the skeleton and then remove the skeleton from the parent Element. Did you try using :
const parentNode=document.querySelector(".parentElem");
parentNode.removeChild(document.querySelector(".skeleton"));
Did you notice you are trying to get an element by using getElementById whereas you stated skeleton is a class.

Javascript updates HTML classes before it is expected to

The problem
I am making Pacman, and I wrote the following function to initialize the board. How is it possible that the board is rendered, even though I only add the styling classes to the square elements in my 'squares' array? As far as I can see I never updated the classes of the div elements inside my 'grid' (which holds the actual div html elements that are shown to the user).
The function
function createBoard() {
for (let i = 0; i < layout.length; i++) {
const square = document.createElement('div')
grid.appendChild(square)
squares.push(square)
if (layout[i] === 0) {
squares[i].classList.add('pac-dot')
} else if (layout[i] === 1) {
squares[i].classList.add('wall')
} else if (layout[i] === 3) {
squares[i].classList.add('power-pellet')
}
}
}
The function iterates through an array (layout) that holds information of how the board should look. For each element of that array a div (square) is created which is then added to the 'grid' (a div element in my html file that holds all newly created divs). The square div is then added to the 'squares' array, which also holds all the square divs, but is not present in my html file.
The second part of the function adds a class to the square in the squares array , based on how the board should look. The result is the following board:
Assuming grid is a DOM element, then grid.appendChild(square) will add the square to the DOM. After that, any change you apply to the element's style will be visible.
So for example, let's say you have the following HTML:
<div id="grid"></div>
Now let's add a child div to it:
const grid = document.getElementById("grid");
const square = document.createElement("div");
grid.appendChild(square);
This actually changes the HTML, to be as if it was written like this:
<div id="grid">
<div></div>
</div>
Adding a class to the div will also change the markup. So after this:
square.classList.add('wall');
The HTML will look like so:
<div id="grid">
<div class="wall"></div>
</div>

.map() img src attribute undefined

Ok so I want to .map() the src values of the html content of #stage to the variable srcArray
var content = $('#stage').html();
var srcArray = $.map($(content), function(el) {
return {value: $(el).children().attr('src')};
});
but when I console.log the array, each src value comes up as undefined. Anyone know what's up?
html is
<div id="stage">
<div style="left:xxx, top:xxx">
<img src="xxxxx" style="width:xxx, height:xxx"/>
</div>
</div>
Do I need to convert the src value to a string to have it show up on the chrome console?
You could get all the img from the #stage element.
var srcArray = $('#stage').find('img').map(function() {
return { value: $(this).attr('src') };
}).get();
Problem :
1. statement return {value: $(el).children().attr('src')}; Will execute for each children of 'div#stage' but stage also have a
div which doesn't have any src attribute.
2. In case 'div#stage'have multipleimg` elements then above statement will return only one result
3. Statement $(content) creating new html elements .Never create new content if you just want to treverse (A bad practice).
Solution :
1. Filter children so that only img tag will be selected.
2. Map on children('img') so that if there are more than 1 img element,code will be executed for each img
3. Use $('#stage') instead of $(content) (which is creating new html elements)
Try this-
var content = $('#stage').html();
var srcArray = $.map($(content).children("img"), function (el) {//better way use $.map($('#stage').children("img"), function (el) {
return {
value: $(el).attr('src')
};
});
console.log(JSON.stringify(srcArray))
Update:-
DEMO
Well the issue is with your children() selection and reading the attribute. It will read the attribute of the first child. So if the first child does not have the attribute it will be undefined. So you need to actually select the element you want. It is also weird you are selecting the html and than building a nodeset based on that html. Just do the selection and use map
var srcArray = $('#stage [src]').map(
function () {
return { value: $(this).attr('src')};
}
);

How to check if an element with id exists or not in jQuery?

I'm generating a div dynamically and I've to check whether a dynamically generated div exists or not ? How can I do that?
Currently I'm using the following which does not detects the div generated dynamically. It only detects if there is already an element with the id contained in the HTML template.
$(function() {
var $mydiv = $("#liveGraph_id");
if ($mydiv.length){
alert("HHH");
}
});
How can I detect the dynamically generated div?
If mutation observes aren't an option due to their browser compatibility, you'll have to involve the code that's actually inserting the <div> into the document.
One options is to use a custom event as a pub/sub.
$(document).on('document_change', function () {
if (document.getElementById('liveGraph_id')) {
// do what you need here
}
});
// without a snippet to go on, assuming `.load()` for an example
$('#container').load('/path/to/content', function () {
$(this).trigger('document_change');
});
If it is added dinamically, you have to test again. Let's say, a click event
$("#element").click(function()
{
if($("#liveGraph_id").length)
alert("HHH");
});
How you inserting your dynamic generated div?
It works if you do it in following way:
var div = document.createElement('div');
div.id = 'liveGraph_id';
div.innerHTML = "i'm dynamic";
document.getElementsByTagName('body')[0].appendChild(div);
if ($(div).length > 0) {
alert('exists'); //will give alert
}
if ($('#liveGraph_id').length > 0) {
alert('exists'); //will give alert
}
if ($('#liveGraph_id_extra').length > 0) {
alert('exists'); //wont give alert because it doesn't exist.
}
jsfiddle.
Just for interest, you can also use a live collection for this (they are provided as part of the DOM). You can setup a collection of all divs in the page (this can be done in the head even before the body is loaded):
var allDivs = document.getElementsByTagName('div');
Any div with an id is available as a named property of the collection, so you can do:
if (allDivs.someId) {
// div with someId exists
}
If the ID isn't a valid identifier, or it's held in a variable, use square bracket notation. Some play code:
<button onclick="
alert(!!allDivs.newDiv);
">Check for div</button>
<button onclick="
var div = document.createElement('div');
div.id = 'newDiv';
document.body.appendChild(div);
">Add div</button>
Click the Check for div button and you'll get false. Add the div by clicking the Add div button and check again—you'll get true.
is very simple as that
if(document.getElementById("idname")){
//div exists
}
or
if(!document.getElementById("idname")){
// don't exists
}

jquery -Get CSS properties values for a not yet applied class

i have a same question asked here(wasnt able to comment on it,maybe dont have a priviledge) , i want to get css width value defined in stylesheet but not yet applied on any element in dom ,(its bootstrap css with grid with responsive media queries)
.span6 {
width: 570px;
}
However solution provided in above referenced question return 0 i.e like this
$('<div/>').addClass('span6').width();
but works if i do something like this
$('<div/>').addClass('span6').hide().appendTo('body').width();
any easy way without appending that div?
In order to read a CSS property value from a nonexistent element, you need to dynamically insert that element (as hidden) to the DOM, read the property and finally remove it:
var getCSS = function (prop, fromClass) {
var $inspector = $("<div>").css('display', 'none').addClass(fromClass);
$("body").append($inspector); // add to DOM, in order to read the CSS property
try {
return $inspector.css(prop);
} finally {
$inspector.remove(); // and remove from DOM
}
};
jsFiddle here
Great answer by Jose. I modified it to help with more complex css selectors.
var getCSS2 = function (prop, fromClass, $sibling) {
var $inspector = $("<div>").css('display', 'none').addClass(fromClass);
if($sibling != null){
$sibling.after($inspector); //append after sibling in order to have exact
} else {
$("body").append($inspector); // add to DOM, in order to read the CSS property
}
try {
return $inspector.css(prop);
} finally {
$inspector.remove(); // and remove from DOM
}
};
JSFiddle

Categories