What to do when function calls a dynamically created element? - javascript

I have tried reading up on my problem and gather event delegation and/or event listeners seem like what I need to do. However, I am confused on the implementation for my script so help would be appreciated.
I can see the problem is probably that the showSlides function references mySlides and grid-box which are dynamically created elements that have not yet been created when the function is called. Is that right? It is a slideshow viewer for context which worked when I did not dynamically create the elements.
The top section is when I did not make the HTML elements dynamically and it worked.
var num_slides = 3
for (let i=1; i<num_slides; i++) {
var $my_slides= $("<div><img style = 'width:100%'/></div>", {"class": "mySlides"});
$('#slideshow-container').prepend($my_slides);
var $grid_box = $("<div><img/></div>", {"class": "grid-box"});
// $(document).on('click','div.grid-box',currentSlide(i)); ​// I've tried this
$grid_box.on('click', function(event){currentSlide(i)});
$('#picture-grid').append($grid_box);
}
function showSlides(n) {
var i;
var slides = document.getElementsByClassName("mySlides");
var gridboxes = document.getElementsByClassName("grid-box");
if (n > slides.length) {slideIndex = 1}
if (n < 1) {slideIndex = slides.length}
for (i = 0; i < slides.length; i++) {
slides[i].style.display = "none";
}
for (i = 0; i < gridboxes.length; i++) {
gridboxes[i].classList.remove("active");
}
slides[slideIndex-1].style.display = "block";
gridboxes[slideIndex-1].className += " active";
}
var slideIndex = 1;
showSlides(slideIndex);
function plusSlides(n) {
showSlides(slideIndex += n);
}
function currentSlide(n) {
showSlides(slideIndex = n);
}
document.onkeydown = function(event) {switch (event.keyCode) {case 37:currentSlide(slideIndex-1);break;case 39:currentSlide(slideIndex+1);break;}};
function onChangeMap(){
const met_var = this.value;
const basepath = '/home/2015_casestudy/';
var startYear = 2014;
var startMon = 1;
document.querySelectorAll('.mySlides img').forEach(function(img, index){
if ((startMon + index) % 12 == 0) {
monthNum = 12;
yearNum = startYear + ((startMon+index) / 12) - 1;
} else {
monthNum = (startMon+index) % 12
yearNum = Math.floor(startYear + ((startMon+index) / 12));
}
var formattedMonthNum = ("0" + monthNum.toString()).slice(-2);
var dateTag = yearNum.toString() + formattedMonthNum
if ((met_var == 'sm_anom_1month' || met_var == 'sm_pct_1month') && (yearNum == 2014)) {
img.src = basepath + "blank.png";
} else {
img.src = basepath + met_var + '_' + dateTag + "?" + new Date().getTime();}
})
document.querySelectorAll('.picture-grid img').forEach(function(img, index){
if ((startMon + index) % 12 == 0) {
monthNum = 12;
yearNum = startYear + ((startMon+index) / 12) - 1;
} else {
monthNum = (startMon+index) % 12
yearNum = Math.floor(startYear + ((startMon+index) / 12));
}
var formattedMonthNum = ("0" + monthNum.toString()).slice(-2);
var dateTag = yearNum.toString() + formattedMonthNum
if ((met_var == 'sm_anom_1month' || met_var == 'sm_pct_1month') && (yearNum == 2014)) {
img.src = basepath + "blank.png";
} else {
img.src = basepath + met_var + '_' + dateTag + "?" + new Date().getTime();}
})
}
window.addEventListener("load",
initPage);
function initPage(){
document.querySelector('#myFormSelect').addEventListener("change", onChangeMap);
document.querySelector('#myFormSelect').dispatchEvent(new Event('change'));
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"
type="text/javascript" charset="utf-8"></script>
<select id="myFormSelect" name="met variables">
<option value="temp" selected='selected'>Temp</option>
<option value="rain">Rainfall</option>
</select>
<div id="slideshow-container" class="slideshow-container">
<a class="prev" onclick="plusSlides(-1)">❮</a>
<a class="next" onclick="plusSlides(1)">❯</a>
</div>
<div id="picture-grid" class="picture-grid"></div>

Where you are created the 's might be running at the same time as the code you have.
Make sure they are created before the code you have. Also, appears that the code is referring to div's with a specific class.
When you are creating the divs in a loop, don't forget to add the appropriate class to match what the code is trying to find.
The code is unable to find the div's either because they are created at the wrong time, or they just don't have the correct id/class names.
var $grid_box = $("<div><img/></div>", {"class": "grid-box"});
Here was your working version: with the missing class name +.correct onClick calls inside the append
var $grid_box = $("<div class='grid-box' onclick='javascript:currentSlide(' + i + ')'><img/></div>');

Related

I can't get the actual number of elements

I'm having a problem returning elements from my object array.
I have a slideshow in which an image (photo of the book) and a text (title of the book) must appear.
For the creation of the slideshow I have no problems because I am using querySelectors as shown in the code below.
The problem lies in showing the images with their titles.
In the first part of the code I have an array of objects that gives me the total number of elements present and based on this I create the slideshow (to create the scroll points and the "container" to contain the images) and then subsequently I call the function myFunction with id argument to return the single element (identified by an id).
What I notice is that the urls with the ids are returned to me, but the url with that id is returned multiple times (so it gets copied) and not just once as expected; I should have only 4 url ​​in total (each with the specific id of the element, since only 4 elements). The same happens when I return the array of objects, it does not return 4 but many more.
Referring to url1:
If I click on the arrows of the slideshow I only receive one image, the other images I do not receive.
I have no mistakes.
var slideIndex = 1;
var outerXmlhttp = new XMLHttpRequest();
var url = "https://wjko8t4509.execute-api.us-east-2.amazonaws.com/books";
outerXmlhttp.onreadystatechange = function () {
var innerXmlhttp;
if (this.readyState == 4 && this.status == 200) {
var allbook = JSON.parse(this.responseText);
for (var i = 0, len = allbook.Items.length; i < len; i++) {
id = allbook.Items[i].id
showSlides(slideIndex);
myFunction(id);
}
}
};
outerXmlhttp.open("GET", url, true);
outerXmlhttp.send();
function plusSlides(n) {
showSlides(slideIndex += n);
}
function currentSlide(n) {
showSlides(slideIndex = n);
}
function showSlides(n) {
var i;
var slides = document.getElementsByClassName("mySlides fade");
var dots = document.getElementsByClassName("dot");
if (n > slides.length) { slideIndex = 1 }
if (n < 1) { slideIndex = slides.length }
for (i = 0; i < slides.length; i++) {
slides[i].style.display = "none";
}
for (i = 0; i < dots.length; i++) {
dots[i].className = dots[i].className.replace(" active", "");
}
slides[slideIndex - 1].style.display = "block";
dots[slideIndex - 1].className += " active";
}
function myFunction(id) {
var url1 = "https://wjko8t4509.execute-api.us-east-2.amazonaws.com/books/" + id;
innerXmlhttp = new XMLHttpRequest();
innerXmlhttp.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
var myArr = JSON.parse(this.responseText);
document.getElementById("img").src = "book_img/" + myArr.Item.immagine;
document.getElementById("title").innerHTML = `${myArr.Item.titolo}`;
}
};
innerXmlhttp.open("GET", url1, true);
innerXmlhttp.send();
}
<div class="slideshow-container" id="slideshow">
<a class="prev" onclick="plusSlides(-1)">❮</a>
<a class="next" onclick="plusSlides(1)">❯</a>
</div>
<br>
<div id="punt" style="text-align:center">
</div>
EDIT
Array allbook with error:
Several things I noticed:
Doesn't define the id
As you state, the data structure from api will look like {"Item":{"marca":"Love","titolo":"You will be missed indefinitely","id":"123456","immagine":"ind.jpg","data":"27/11/2021"}}, but are trying to loop over all the item inside item which will be incorrect, you should loop over allbook.
It should be allbook[i].Items.length instead of allbook.Items.length
var slideIndex = 1;
let id;
var outerXmlhttp = new XMLHttpRequest();
var url = "https://wjko8t4509.execute-api.us-east-2.amazonaws.com/books";
outerXmlhttp.onreadystatechange = function() {
var innerXmlhttp;
if (this.readyState == 4 && this.status == 200) {
var allbook = JSON.parse(this.responseText);
for (var i = 0, len = allbook.length; i < len; i++) {
id = allbook[i].Items.id
document.querySelector('.slideshow-container').innerHTML += `
<div class="mySlides fade">
<div class="numbertext">${i+1}/${allbook[i].Items.length}</div>
<img id="img" src onerror="this.onerror=null; this.src=myFunction(${id});" style="width:100%">
<div class="text" id="title" onclick="myFunction(${id})"></div>
</div>`;
document.querySelector('#punt').innerHTML += `
<span class="dot" onclick=currentSlide(${i+1})></span>`;
myFunction(id);
}
showSlides(0);
}
};
outerXmlhttp.open("GET", url, true);
outerXmlhttp.send();
function plusSlides(n) {
showSlides(slideIndex += n);
}
function currentSlide(n) {
showSlides(slideIndex = n);
}
function showSlides(n) {
var i;
var slides = document.getElementsByClassName("mySlides fade");
var dots = document.getElementsByClassName("dot");
if (n > slides.length) {
slideIndex = 1
}
if (n < 1) {
slideIndex = slides.length
}
for (i = 0; i < slides.length; i++) {
slides[i].style.display = "none";
}
for (i = 0; i < dots.length; i++) {
dots[i].className = dots[i].className.replace(" active", "");
}
slides[slideIndex - 1].style.display = "block";
dots[slideIndex - 1].className += " active";
}
function myFunction(id) {
var url1 = "https://wjko8t4509.execute-api.us-east-2.amazonaws.com/books/" + id;
innerXmlhttp = new XMLHttpRequest();
innerXmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var myArr = JSON.parse(this.responseText);
document.getElementById("img").src = "book_img/" + myArr.Item.immagine;
document.getElementById("title").innerHTML = `${myArr.Item.titolo}`;
}
};
innerXmlhttp.open("GET", url1, true);
innerXmlhttp.send();
}
<div class="slideshow-container" id="slideshow">
<a class="prev" onclick="plusSlides(-1)">❮</a>
<a class="next" onclick="plusSlides(1)">❯</a>
</div>
<br>
<div id="punt" style="text-align:center">
</div>

How do I change image of a slider closed in another function?

what I have in here is a simple slider with two images. Is there a way to change the var file of imageSwap() when the counter hits 12?
var number = Math.floor(Math.random() * 2) + 1;
var timer1 = 0;
var timer2 = 0;
function imageSwap(id) {
var img = document.getElementById("app" + id);
img.src = "red.png";
img.classList.add("selected");
var count = document.querySelectorAll(".selected").length;
console.log(count);
if (count == 12) {
// Change var file image of function Change()
}
}
function hide() {
$("#slider").fadeOut(500);
}
function change() {
number++;
if (number > 2) number = 1;
var file = '<img src="tree' + number + '.png" />';
document.getElementById("slider").innerHTML = file;
$("#slider").fadeIn(500);
timer1 = setTimeout("change()", 5000);
timer2 = setTimeout("hide()", 4500);
}
Thanks in advance!

JavaScript increase and decrease font size

I am new to JavaScript. I would like to add to add two buttons for my visitors to control font size. I would like to include two tags - 'p' and 'blockquote". Can you please help me edit this code in order to include both?
var min = 8;
var max = 18;
function increaseFontSize() {
var p = document.getElementsByTagName('p');
for (i = 0; i < p.length; i++) {
if (p[i].style.fontSize) {
var s = parseInt(p[i].style.fontSize.replace("px", ""));
} else {
var s = 12;
} if (s != max) {
s += 1;
}
p[i].style.fontSize = s + "px"
}
}
function decreaseFontSize() {
var p = document.getElementsByTagName('p');
for (i = 0; i < p.length; i++) {
if (p[i].style.fontSize) {
var s = parseInt(p[i].style.fontSize.replace("px", ""));
} else {
var s = 12;
} if (s != min) {
s -= 1;
}
p[i].style.fontSize = s + "px"
}
}
Thank you.
Here's a working version:
http://jsfiddle.net/ny4p7pg9/
I took the liberty of refactoring a bit the functions to make the code more parameterized.
function changeFontSize(delta) {
var tags = document.querySelectorAll('p,blockquote');
for (i = 0; i < tags.length; i++) {
if (tags[i].style.fontSize) {
var s = parseInt(tags[i].style.fontSize.replace("px", ""));
} else {
var s = 12;
} if (s != max) {
s += delta;
}
tags[i].style.fontSize = s + "px"
}
}
function increaseFontSize() {
changeFontSize(1);
}
function decreaseFontSize() {
changeFontSize(-1);
}
Instead of using:
p = document.getElementsByTagName('p');
you could, instead use:
elems = document.querySelectorAll('p, blockquote');
(the variable name is irrelevant, and was changed only because the elements are no longer exclusively <p> elements):
function increaseFontSize() {
var elems = document.querySelectorAll('p, blockquote');
for (i = 0; i < elems.length; i++) {
if (elems[i].style.fontSize) {
var s = parseInt(elems[i].style.fontSize.replace("px", ""));
} else {
var s = 12;
} if (s != max) {
s += 1;
}
elems[i].style.fontSize = s + "px"
}
}
var min = 8;
var max = 18;
function increaseFontSize() {
var elems = document.querySelectorAll('p, blockquote');
for (i = 0; i < elems.length; i++) {
if (elems[i].style.fontSize) {
var s = parseInt(elems[i].style.fontSize.replace("px", ""));
} else {
var s = 12;
} if (s != max) {
s += 1;
}
elems[i].style.fontSize = s + "px"
}
}
function decreaseFontSize() {
var elems = document.querySelectorAll('p, blockquote');
for (i = 0; i < elems.length; i++) {
if (elems[i].style.fontSize) {
var s = parseInt(elems[i].style.fontSize.replace("px", ""));
} else {
var s = 12;
} if (s != min) {
s -= 1;
}
elems[i].style.fontSize = s + "px"
}
}
document.querySelector('#increase').addEventListener('click', increaseFontSize);
document.querySelector('#decrease').addEventListener('click', decreaseFontSize);
<button id="increase">↑A</button>
<button id="decrease">A↓</button>
<p>Some text to have its text adjusted by the buttons just up there.</p>
<blockquote>Some text in a blockquote</blockquote>
The querySelectorAll() method accepts CSS-style selectors, and returns a (non-live) NodeList, and is supported in all modern browsers, including IE from version 8 onwards.
That said, it's probably better to increase the font-size of the <body> element, otherwise font-adjustment is redundant (since other elements will still be unclear), so, instead, I'd suggest:
function increaseFontSize() {
// retrieving, and caching, the <body> element:
var body = document.body,
// finding the current computed fontSize of the <body> element, parsing it
// as a float (though parseInt() would be just as safe, really):
currentFontSize = parseFloat(window.getComputedStyle(body, null).fontSize);
// if the currentFontSize is less than the specified max:
if (currentFontSize < max) {
// we set the fontSize of the <body> to the incremented fontSize,
// increasing the current value by 1, and concatenating with the 'px' unit:
body.style.fontSize = ++currentFontSize + 'px';
}
}
function decreaseFontSize() {
var body = document.body,
currentFontSize = parseFloat(window.getComputedStyle(body, null).fontSize);
if (currentFontSize > min) {
body.style.fontSize = --currentFontSize + 'px';
}
}
var min = 8;
var max = 18;
function increaseFontSize() {
var body = document.body,
currentFontSize = parseFloat(window.getComputedStyle(body, null).fontSize);
if (currentFontSize < max) {
body.style.fontSize = ++currentFontSize + 'px';
}
}
function decreaseFontSize() {
var body = document.body,
currentFontSize = parseFloat(window.getComputedStyle(body, null).fontSize);
if (currentFontSize > min) {
body.style.fontSize = --currentFontSize + 'px';
}
}
document.querySelector('#increase').addEventListener('click', increaseFontSize);
document.querySelector('#decrease').addEventListener('click', decreaseFontSize);
<button id="increase">↑A</button>
<button id="decrease">A↓</button>
<p>Some text to have its text adjusted by the buttons just up there.</p>
<blockquote>Some text in a blockquote</blockquote>
References:
document.body.
document.querySelectorAll().
Window.getComputedStyle().

How To Change Image in Array Based on Textbox input in JavaScript?

I'm trying to make my page so a user can type a number value between 1 and 200 to get to whichever image they want to view. I've played around with the code, but I can't seem to get anything to work. Below is my code that I've tried to do this with. What am I doing wrong?
Edit: New Code:
`
<html>
<head>
<title></title>
</head>
<body style="background-color: teal;">
<form>
<center>
<div width="50%" style="width: 50%;">
<div id="main" align="middle">
<img src="page1.jpg" alt="" id="mainImg" height="90%">
</div>
<div id="imglist">
<a href="javascript:previousImage('mainImg')"><img src="previous.png" alt=""
align="left"></a>
<input id="myid" name="myid" size="3" type="text"></input>
<img src="next.png" alt="" align="right">
<script>
var imgArray = new Array();
var imgs = [];
for (var i = 0; i < 200; i++) {
imgs[i] = new Image();
imgs[i].src = "page" + (i + 1) + ".jpg";
}
function nextImage(element)
{
var img = document.getElementById(element);
for(var i = 0; i < imgArray.length;i++)
{
if(imgArray[i].src == img.src) // << check this
{
if(i === imgArray.length){
document.getElementById(element).src = imgArray[0].src;
break;
}
document.getElementById(element).src = imgArray[i+1].src;
break;
}
}
}
function previousImage(element)
{
var img = document.getElementById(element);
for(var i = 0; i < imgArray.length;i++)
{
if(imgArray[i].src == img.src)
{
if(i === 0){
document.getElementById(element).src = imgArray[imgArray.length-1].src;
break;
}
else{
document.getElementById(element).src = imgArray[i-1].src;
break;
}
}
}
}
window.onload = function() {
var elm = document.getElementById("myid"),
var img = document.getElementById("mainImg");
elm.onkeyup = function(event) {
if (this.value) {
var num = parseInt(this.value, 10);
if (num >= 1 && num <= 200 {
img.src = "page" + num + ".jpg";
}
}
}
}
</script>
</div>
</div>
</center>
</form>
</body>
</html>
Perhaps you mean for this:
if (this.value.length === 1,2,3) {
to be this:
if (this.value.length <= 3) {
In addition, I think you want to be converting the whole input value to a number, not using the individual keycodes.
I might suggest this different/simpler way of doing this that is much more DRY (don't repeat yourself):
// preload images
var imgs = [];
for (var i = 0; i < 200; i++) {
imgs[i] = new Image();
imgs[i].src = "page" + (i + 1) + ".jpg";
}
window.onload = function() {
var elm = document.getElementById("myid");
var img = document.getElementById("mainImg");
elm.onkeyup = function(event) {
if (this.value) {
var num = parseInt(this.value, 10);
if (num >= 1 && num <= 200) {
img.src = "page" + num + ".jpg";
}
}
}
}
Working Demo: http://jsfiddle.net/jfriend00/4dqbP/
Summary of changes:
Preload images in a loop rather than copied code
Construct image names dynamically
Make img variable to a local variable rather than an implicit global with var in front of it
Check to see if the input field is empty
Use parseInt() to parse the value of the input field into a number
Range check the parsed number
If in valid range, then construct the image name using that number

removing html element styles via javascript

I'm trying to replace an element's inline style tag value. The current element looks like this:
`<tr class="row-even" style="background: red none repeat scroll 0% 0%; position: relative; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;" id="0000ph2009-06-10s1s02">`
and I'd like to remove all that style stuff so that it's styled by it's class rather than it's inline style. I've tried delete element.style; and element.style = null; and element.style = ""; to no avail. My current code breaks at these statement. The whole function looks like:
function unSetHighlight(index){
if(index < 10)
index = "000" + (index);
else if (index < 100)
index = "000" + (index);
else if(index < 1000)
index = "0" + (index);
if(index >= 1000)
index = index;
var mainElm = document.getElementById('active_playlist');
var elmIndex = "";
for(var currElm = mainElm.firstChild; currElm !== null; currElm = currElm.nextSibling){
if(currElm.nodeType === 1){
var elementId = currElm.getAttribute("id");
if(elementId.match(/\b\d{4}/)){
elmIndex = elementId.substr(0,4);
if(elmIndex == index){
var that = currElm;
//that.style.background = position: relative;
}
}
}
}
clearInterval(highlight);
alert("cleared Interval");
that.style.background = null;
alert("unSet highlight called");
}
the clearInterval works but the alert never fires and the background stays the same. What's the problem?
function unSetHighlight(index){
alert(index);
if(index < 10)
index = "000" + (index);
else if (index < 100)
index = "000" + (index);
else if(index < 1000)
index = "0" + (index);
if(index >= 1000)
index = index;
var mainElm = document.getElementById('active_playlist');
var elmIndex = "";
for(var currElm = mainElm.firstChild; currElm !== null; currElm = currElm.nextSibling){
if(currElm.nodeType === 1){
var elementId = currElm.getAttribute("id");
if(elementId.match(/\b\d{4}/)){
elmIndex = elementId.substr(0,4);
alert("elmIndex = " + elmIndex + "index = " + index);
if(elmIndex === index){
var that = currElm;
alert("match found");
}
}
}
}
clearInterval(highlight);
alert("cleared Interval");
that.removeAttribute("style");
//that.style.position = "relative";
//reColor();
alert("unSet highlight called");
}
you can just do:
element.removeAttribute("style")
In JavaScript:
document.getElementById("id").style.display = null;
In jQuery:
$("#id").css('display',null);
getElementById("id").removeAttribute("style");
if you are using jQuery then
$("#id").removeClass("classname");
The class attribute can contain multiple styles, so you could specify it as
<tr class="row-even highlight">
and do string manipulation to remove 'highlight' from element.className
element.className=element.className.replace('hightlight','');
Using jQuery would make this simpler as you have the methods
$("#id").addClass("highlight");
$("#id").removeClass("hightlight");
that would enable you to toggle highlighting easily
Use
particular_node.classList.remove("<name-of-class>")
For native javascript
Remove removeProperty
var el=document.getElementById("id");
el.style.removeProperty('display')
console.log("display removed"+el.style["display"])
console.log("color "+el.style["color"])
<div id="id" style="display:block;color:red">s</div>
In jQuery, you can use
$(".className").attr("style","");
Completly removing style, not only set to NULL
document.getElementById("id").removeAttribute("style")

Categories