Prevent createElement from creating multiple identical images - javascript

I am going to try and be as thorough as possible on this so stick with me.
My program takes user input entered on a form. This input goes through a range of if statements that will set variables to true, these variables that are set to true will then use createElement to create img inside predetermined divs. There will always be at least one img created, and up to 4 imgs at the most. This is all completed by a button click.
I learned createElement will continuously createElement with each button click posting the img right next to the original img and will do this infinitely or until the page is reloaded.
My solution was to create a counter that incremented each time the button was clicked. That took care of any extra createElements. Then I thought if the user first entered a large number that will create 2 separate and individual images say... image 1 and image 2 (which is desired), then if the user enters a lower number that only creates image 1, then image 2 would still be posted (unwanted). Of course a page refresh would clear the images created and avoid this.
So I'm not quite sure what to do...
Ideally when the button is pressed a second time then all old createElements would be cleared, and all new createElements would populate.
I removed the counter for the purpose of this question
poster__#'s are the called id's...
const movieTime = 30;
var userTimeAvailable = 25;
const button = document.getElementById("calculate");
button.onclick = function calculateTime() {
if (userTimeAvailable < movieTime) {
console.log(
"You have enough time to watch " +
Math.round((userTimeAvailable / movieTime) * 100) +
"% of the movie."
);
displayMoviePoster1 = true;
}
moviePosterGenerator();
}
function moviePosterGenerator() {
if (displayMoviePoster1 === true) {
var par = document.getElementById("poster__2");
var theatricalMoviePoster = document.createElement("img");
theatricalMoviePoster.src = "imgURL";
par.appendChild(theatricalMoviePoster);
}
}
<button class="button" id="calculate">calculate</button>
<div class="movie-poster__container" id="posters">
<div class="movie-poster" id="poster__1"></div>
<div class="movie-poster" id="poster__2"></div>
<div class="movie-poster" id="poster__3"></div>
<div class="movie-poster" id="poster__4"></div>
</div>

Related

Prevent Image Caching - Javascript

This function is supposed to grab a random image from the url everytime its called
function grabImg(){
var img = document.createElement('img');
img.src = 'https://picsum.photos/200/300';
document.getElementById('flex-cat').appendChild(img);
}
And display it in the div below
<div class="container-1">
<h2>Image Grabber</h2>
<button class="btn btn-success" onclick="grabImg()">Grab Image</button>
<div class="flex-box-container-2" id="flex-cat"></div>
</div>
Initially when the button is clicked, it calls the function and displays an image fine. However when the button is clicked on multiple times, instead of displaying different random images, the same image which was shown the first time keeps being displayed.
Any tips on how to prevent this?
Using picsum documentation, see Advanced Usage, you can request multiple images of the same size in your browser, add the random query param to prevent the images from being cached. Then you can randomize the number using a helper function, then concatenate using string literal => img.src = https://picsum.photos/200/300?random=${randomRange(10000)}.
EDIT:
To make it truly random, track the random numbers created with the helper function using an array. If the value is present in the array already, then run the randomImage method again, else push the value into the array for tracking purposes and return the random value.
const arr = []
function randomImage() { // get a random number
let num = ''
let tempRan = Math.random()
if(!arr.includes(tempRan)){
num = tempRan
arr.push(num)
}else{
randomImage()
}
return arr[arr.length-1]
}
function grabImg() {
var img = document.createElement('img');
img.src = `https://picsum.photos/200/300?random=${randomImage()}`;
document.getElementById('flex-cat').appendChild(img);
}
<div class="container-1">
<h2>Image Grabber</h2>
<button class="btn btn-success" onclick="grabImg()">Grab Image</button>
<div class="flex-box-container-2" id="flex-cat">
</div>
</div>

Function executes only once when using onClick event [javascript]

I am trying to randomly change background image of a div (#reaction-background) after every click of a button (#angry) with onclick event.
However, the background image only changes once after clicking the button.
HTML:
<div class="btn-list">
<a id="angry">ANGRY</a>
<div id="reaction-background"></div>
Javascript:
// array of pictures
var fileNamesReactions = [
"angry1.jpg",
"angry2.jpg",
"angry3.jpg",
"angry4.jpg",
"angry5.jpg"
];
// random reaction index
var randomIndexReaction = Math.floor(Math.random() * fileNamesReactions.length);
// randomize pictures
document.getElementById("angry").onclick = function() {
document.getElementById("reaction-background").style.background = "url(./img/reactions/angry/" + fileNamesReactions[randomIndexReaction] + ")";
document.getElementById("reaction-background").style.backgroundRepeat = "no-repeat";
document.getElementById("reaction-background").style.backgroundSize = "contain";
}
Your click event handler is, in fact, running every time you click. The problem is that you are only generating a random number once, before any clicks happen and so you set the background image once and further clicks just set the same image over and over.
You need to move the random generator inside of the click callback so that a new random number is generated upon each click.
Also, don't use the onclick property of the element to set up the callback. While this approach works, it's outdated and you should use the more robust and standard .addEventListener() method to set up events.
In addition, do your styling in CSS as much as possible and use CSS classes.
Putting it all together:
// array of pictures
var fileNamesReactions = [
"angry1.jpg",
"angry2.jpg",
"angry3.jpg",
"angry4.jpg",
"angry5.jpg"
];
// Get your DOM references that you'll use repeatedly just once:
let backgroundElement = document.getElementById("reaction-background");
// randomize pictures
document.getElementById("angry").addEventListener("click", function() {
// You have to get a new random each time the click occurs.
var random = Math.floor(Math.random() * fileNamesReactions.length);
backgroundElement.style.background = "url(./img/reactions/angry/" + fileNamesReactions[random] + ")";
console.log(backgroundElement.style.background);
});
/* Use CSS classes as much as possible as they make code much simpler */
#reaction-background {
background-size:"contain";
background-repeat:"no-repeat";
}
<div class="btn-list">
<a id="angry">ANGRY</a>
<div id="reaction-background"></div>
</div>
Move the random number statement inside the onclick method so that it generate a new number on every click. Please find code below:
// array of pictures
var fileNamesReactions = [
"angry1.jpg",
"angry2.jpg",
"angry3.jpg",
"angry4.jpg",
"angry5.jpg"
];
// randomize pictures
document.getElementById("angry").onclick = function() {
// random reaction index
var randomIndexReaction = Math.floor(Math.random() * fileNamesReactions.length);
document.getElementById("reaction-background").style.background = "url(./img/reactions/angry/" + fileNamesReactions[randomIndexReaction] + ")";
document.getElementById("reaction-background").style.backgroundRepeat = "no-repeat";
document.getElementById("reaction-background").style.backgroundSize = "contain";
}

Dynamically add input values to dynamically added input boxes

I have a song submission form on my site. When an artist uploads a song, I developed JS to calculate the beats per minute (BPM) and duration of the song. Once calculated, it populates the two corresponding input boxes (Duration and BPM) on the form. The code I have works perfectly if a single song is submitted, however, the form allows multiple song uploads per form submission. Since these new input boxes are added dynamically, I'm not quite sure how I can get the new songs to dynamically update the value of the bpm/duration since the new input boxes are loaded by JS. There's a decent amount of code below, please let me know if you need more clarification:
The user can dynamically add another song by clicking the "Add another song" button loaded through JS:
<div id="dynamicInput"></div>
<input type="button" id="add-song-btn" value="Add another song" onClick="addInput('dynamicInput');">
Corresponding JS:
var counter = 1;
var limit = 20;
function addInput(divName)
{
if(counter == limit)
{
alert("You have reached the limit of adding " + counter + " inputs");
}
else
{
var newdiv = document.createElement('div');
{
newdiv.innerHTML = "<hr>Song #" + (counter + 1) + " " + "<input type='hidden' role='uploadcare-uploader' data-max-size='120000000' name='song-submission'data-crop='disabled' /><input type='text' id='duration' name='submit-duration' placeholder='Duration: '3:11'><input type='number' id='bpm' name='submit-bpm' placeholder='BPM: 128'>";
document.getElementById(divName).appendChild(newdiv);
}
counter++;
setTimeout(function () {
uploadcare.initialize();
}, 0);
}
};
When a user uploads a song by using the "Choose a file" button, this is the corresponding input box:
<input name="song-submission" type="hidden" role="uploadcare-uploader" data-max-size="120000000" data-file-types="mp3" data-crop="disabled">
When uploaded, the submission creates a src url that I add to an audio HTML src tag that triggers two different JS functions. When the upload completes the JS code widget.onUploadComplete runs. Here's that audio tag and the corresponding code that loads the src url into that html code:
<audio id="myAudio" controls onloadedmetadata="setDuration()">
<source src="">
</audio>
JS
var widget = uploadcare.Widget('[role=uploadcare-uploader]');
widget.onUploadComplete(function(info) {
var previewUrl = info.cdnUrl;
document.getElementById('myAudio').src = info.cdnUrl;
//code to calculate BPM is found here///
document.getElementById('bpm').value = Math.round(top[0].tempo);
};
};
request.send();
});
When the src url is added to the HTML audio id="myAudio" tag, the JS waits until onloadedmetadata to run a function ( setDuration()) to determine the duration:
function setDuration() {
var time = document.getElementById('myAudio').duration;
// code to calculate duration //
ret += "" + mins + ":" + (secs < 10 ? "0" : "");
ret += "" + Math.round(secs);
document.getElementById('duration').value = ret;
return ret;
}
So here is where I'm at, and my code does not work with dynamically loaded input boxes. First thing is that once a new song submission input is added, there would be two input boxes with role=uploadcare-uploader which would cause issues with the widget JS variable right off the bat, I think that's where we need to start first. Any thoughts?
PROBLEM
When you initialize new uplaodcare instance (deferred) it doesn't register onUploadComplete events for those newly created widgets, because only on that moment when you execute uploadcare.Widget('[role=uploadcare-uploader]'); first child only (another problem of your code) gets the event listener registered.
Element argument can be a DOM element, a jQuery object, or a CSS selector. >If element’s argument is a CSS selector, only the instance for the first >matched element will be returned. To make sure you get the right instance >when there are multiple widgets on the page, select by id or pass in a DOM element.
SOLUTION
Execute your code after each uploadcare instance creating and use unique selector to get proper widget:
setTimeout(function () {
uploadcare.initialize();
var widget = uploadcare.Widget('#song-uploader-<1..N>'); // Generate this when DIV adding
widget.onUploadComplete(function(info) {
var previewUrl = info.cdnUrl;
document.getElementById('myAudio').src = info.cdnUrl;
//code to calculate BPM is found here///
document.getElementById('bpm').value = Math.round(top[0].tempo);
};
};
request.send();
});
}, 0);
You can omit the handler into its own function to keep code cleaner and write widget.onUploadComplete(calculateBPM)
Have a look at the API documentation:
There it says:
Initializes widget instances once (either single-upload, or
multi-upload) on every element with role="uploadcare-uploader"
attribute in a container, specified by selector or DOM element. If
container is absent the document is used. Returns array of new
initialized widgets, or empty array if no new instances were
initialized.
var widgets = uploadcare.initialize('#my-form');
widgets; // [widget1, widget2, multipleWidget1, ...]
var widgets = uploadcare.initialize();
So from that point you can go on. (e.g. giving the input box an id and call your js function on every input box with that id).

Permanent change to 1 div out of many of the same

I have stumbled on to a problem which I cannot find the solution to, for some time now, and it is kind of a drag, but hey, I will try to be as precice as possible, there is no stupid question so here goes.
This is a DIV table for appointments and a page, these green circles are divs also and there are 209 divs total, divs are clickable and once clicked they open up a new page in a new tab which asks the user to to enter his info Name, Last Name etc. and make an appointment.
When the user enters what is asked of him he clicks a button makes an appointment and the div that has been clicked in the previous "table" page permanently changes color to red, so when someone else visits the "table" page sees that the time for the appointment is unavailable.
I have come up with this.
TABLE PAGE CODE:
<script type="text/javascript">
window.onload = function () {
var myLoadedColor = localStorage.getItem('myDataStorage');
document.getElementById('L1').style.backgroundColor = myLoadedColor;
var d = document.getElementsByClassName("circleBase type1");
for(var i = 0; i < d.length; i++) {
d[i].onclick = function() {
window.open("EnterInformation.html");
}
}
}
window.addEventListener('storage', function (event) {
if (event.storageArea === localStorage) {
var myLoadedColor = localStorage.getItem('myDataStorage');
document.getElementById('L1').style.backgroundColor = myLoadedColor;
}
}, false);
APPOINTMENT PAGE CODE:
function SaveInfo() {
localStorage.Yritys = $('#Yritys').val();
localStorage.Henkilönimi = $('#Henkilönimi').val();
localStorage.Asema_yrityksessa = $('#Asema_yrityksessa').val();
localStorage.Puhelin_Nr = $("#Puhelin_Nr").val();
localStorage.e_Mail = $('#e_Mail').val();
localStorage.Keskustelun_aihe = $('#Keskustelun_aihe').val();
alert("You have successfully made an appointment");
}
function closeSelf() {
window.close(this);
}
function changeColor() {
myCustomColor = 'red';
localStorage.setItem('myDataStorage', myCustomColor);
}
With this code It works but only for 1 div the first one.
My question is do I have to add Id to all of the 209 divs I have and then copy this code 209 times for each and every one of the divs and create a specific storage for each of them? or is there an easier way to do this?
Ajax is like an acquaintance to me.
Any advice would be helpful if it helps me achieve this goal, because I can't sleep and keep thinking about the ways to end the agony!

choose image in array and continue

First time JavaScript coder here.
Trying to solve this so that an image is displayed when the appropriate button for that image is clicked and then the function continues to show the other image in the Array and loops.
For instance if the banner is displaying image 4 and the user clicks on the button for image 2, then the banner should display image 2 and then rotate to show image 3 and continue looping.
Here is the code:
var i = 0;
var baners = new Array();
baners.push('banner1.jpg');
baners.push('banner2.jpg');
baners.push('banner3.jpg');
baners.push('banner4.jpg');
baners.push('banner5.jpg');
function swapImage(){
var img = document.getElementById("banner");
img.src = baners[i];
if (i<(baners.length-1)){i++;
}else{
i=0;
}
setTimeout('swapImage()', 2000);
}
function button1 (){
var img = document.getElementById("banner");
img.src = baners[0]
}
I am unsure if it is possible to make one global function for the 5 buttons.
Thank you!
I am unsure if it is possible to make one global function for the 5 buttons.
Yes. Use something like this:
function buttonClicked(number) {
var img = document.getElementById("banner");
img.src = baners[number]
i = number; // set current loop position
}
then call buttonClicked(0) from button1, buttonClicked(1) from button2 and so on. If you want to automatically attach the handlers to the button using a for-loop, check out JavaScript closure inside loops – simple practical example.

Categories

Resources