Making a clickable image disappear after 10 clicks - javascript

I'm new to JavaScript and I need an image to "disappear" after clicking on it 10 times. What code do I use to make that happen?

You can use a counter variable to keep track of the number of clicks.
Your HTML:
<img src='your-img.jpg'/>
Your JavaScript:
const img = document.querySelector('img'); // Selects the image in your HTML.
let numberOfClicks = 0; // Initialize the counter
const advanceCounter = () => numberOfClicks++; // This is a function that if called, advances the counter by 1.
// Apply a 'click' event listener
img.onclick = function(ev) {
if (numberOfClicks >= 10)
this.style.display = 'none'
else advanceCounter()
}

You can done this with single line of code
<img src="/test.png" onclick="window.counter=(window.counter??0)+1;window.counter>=10?this.remove():null">
window.counter is global variable which increment and if its reach 10 click its will remove its own element

Related

Javascript pop up on multiple elements

I am trying to build a pop-up function written in JavaScript but I feel the code could be better.
So I have two thumbnails and when click it shows the corresponding image but bigger.
I want to build a page with about 20 of these but I feel there will be a lot of code repetition and I am stuck.
My code is here:
https://codesandbox.io/s/i8b1s
Here is my JS:
/*
The goal of this is to simplify the JS code as when I add more images
I do want to keep duplicating code.
*/
// Tesing
const targetNum = document.querySelectorAll("target");
console.log(targetNum);
// Original code below
// Target 1
const target1 = document.querySelector(".counterNo1");
const target2 = document.querySelector(".counterNo2");
// Target 1 Pop Up
const target1MainImage = document.querySelector(".mainImage1");
const target2MainImage = document.querySelector(".mainImage2");
// Close buttons
const close1 = document.querySelector(".closeBTN1");
const close2 = document.querySelector(".closeBTN2");
//Target 1 Clicked Event
target1.addEventListener("click", function () {
console.log("Target 1");
target1MainImage.classList.remove("hide");
target1MainImage.classList.add("show");
});
//Target 2 Clicked Event
target2.addEventListener("click", function () {
console.log("Target 2");
target2MainImage.classList.remove("hide");
target2MainImage.classList.add("show");
});
// Close
//Close Event 1
close1.addEventListener("click", function () {
console.log("Close Target 1");
target1MainImage.classList.add("hide");
target1MainImage.classList.remove("show");
});
//Close Event 2
close2.addEventListener("click", function () {
console.log("Close Target 2");
target2MainImage.classList.add("hide");
target2MainImage.classList.remove("show");
});
As you can see if I have more that one pop up, I am duplicating event listeners etc and I do not want a lot of dup code for elements. This is where I am stuck.
Can anyone point me in the right direction on what to do please?
Thanks,
Ben.
so what you can do is create a common popup and let there be 20 targets on the page. so all you have to do then is
// here create a variable to map the location or src value of bigger image
const ImageMapper = {
one: '/images/one.jpg'
.....
}
// then create the function which calls the popup and set the src of the image element in it
const openPopup = (opener) => {
popupImage.src = ImageMapper[opener]
popup.classList.add('show')
}
// and in the poup add a button which closes the popup so that you dont have to write multiple functions just to close a single popup
const closePopup = () => {
popup.classList.add('hide')
}
// and last in each of the possible element that will open the popup just add the onclick handler like
target1.onclick = () => {
openPopup('one')
}
// this will require a lot less code then what you will have to write

Add delay to mousemove event

I have this function running on a mousemove event. The functionality is to iterate a list of images and move to the top (z-index) each one at a time. This is working right but my problem is that the script is running really fast and the images displays really fast. How can I add a delay to the function or the event? I tried with setTimeOut with no positive effects
Here's the code
// creating variables
const imgQty = 6;
const holder = document.getElementById('holder')
var counter = 1;
var isMoving = false;
var bgtimeout, imgtimeout;
var bkgImgs = []
// this creates the containers for each img
for (let i = 1; i <= imgQty; i++) {
var newDiv = document.createElement('div');
newDiv.classList.add('background')
newDiv.classList.add(`background--${i}`)
newDiv.setAttribute("style", `background-image: url('imgs/${i}.jpg'); z-index: 0;`);
holder.appendChild(newDiv);
bkgImgs.push(newDiv)
}
//this moves the counter and also hides the images when the mouse is not moving
function changeBkg(e){
counter >= imgQty ? counter = 1 : counter++
holder.classList.add('isActive')
clearTimeout(bgtimeout);
clearTimeout(imgtimeout);
bgtimeout = setTimeout(function(){holder.classList.remove('isActive')}, 150);
moveImgs();
}
// and here is where my issue is, this function is working but not as I expected
function moveImgs(){
for(var i = 0; i < bkgImgs.length; i++){
if(bkgImgs[i].classList.contains(`background--${counter}`)){
bkgImgs[i].style.zIndex = "1";
} else{
bkgImgs[i].style.zIndex = "0";
}
}
}
Is my logic right? or do I have to rethink the code?
the event is fired in the section:
<section class="main" onmousemove="changeBkg(event)"></section>
Use Debounce
Something like this should work (remove the timeout from inside changeBkg):
//change 300ms to suite your needs
<section class="main" onmousemove="debounce(changeBkg(event),300)"></section>
A debounce is a higher-order function, which is a function that returns another function. This is done to form a closure around the func , wait , and immediate function parameters and the timeout variable so that their values are preserved.
Further reading/if you prefer to implement yourself: Debounce Article
It has been resolved.
As what I needed was some sort of animation I figured it out using greensock
So my event have inside this animation that triggers when animPlay is true and when is playing remains false
if(animPlay){
animPlay = false
var tl = new TimelineMax();
tl.staggerFromTo(bkgImgs, .5, {zIndex:0}, {zIndex:1}, .15, 0)
.set(bkgImgs, {zIndex:0, onComplete:() => animPlay = true}, '+=0' )
}

javascript/html: Second onclick attribute

I have an image - image1.png. When I click a button the first time, I want it to change to image2.png. When I click the button for a second time, I want it to change to another image, image3.png.
So far I've got it to change to image2 perfectly, was easy enough. I'm just stuck finding a way to change it a second time.
HTML:
<img id="image" src="image1.png"/>
<button onclick=changeImage()>Click me!</button>
JavaScript:
function changeImage(){
document.getElementById("image").src="image2.png";
}
I'm aware I can change the image source with HTML within the button code, but I believe it'll be cleaner with a JS function. I'm open to all solutions though.
You'll need a counter to bump up the image number. Just set the maxCounter variable to the highest image number you plan to use.
Also, note that this code removes the inline HTML event handler, which is a very outdated way of hooking HTML up to JavaScript. It is not recommended because it actually creates a global wrapper function around your callback code and doesn't follow the W3C DOM Level 2 event handling standards. It also doesn't follow the "separation of concerns" methodology for web development. It's must better to use .addEventListener to hook up your DOM elements to events.
// Wait until the document is fully loaded...,
window.addEventListener("load", function(){
// Now, it's safe to scan the DOM for the elements needed
var b = document.getElementById("btnChange");
var i = document.getElementById("image");
var imgCounter = 2; // Initial value to start with
var maxCounter = 3; // Maximum value used
// Wire the button up to a click event handler:
b.addEventListener("click", function(){
// If we haven't reached the last image yet...
if(imgCounter <= maxCounter){
i.src = "image" + imgCounter + ".png";
console.log(i.src);
imgCounter++;
}
});
}); // End of window.addEventListener()
<img id="image" src="image1.png">
<button id="btnChange">Click me!</button>
For achieve your scenario we have to use of counter flag to assign a next image. so we can go throw it.
We can make it more simple
var cnt=1;
function changeImage(){
cnt++;
document.getElementById("image").src= = "image" + cnt + ".png";
}
try this
function changeImage(){
var img = document.getElementById("image");
img.src = img.src == 'image1.png' ? "image2.png" : "image3.png";
}
Just use an if statement to determine what the image's source currently is, like so:
function changeImage(){
var imageSource = document.getElementById("image").src;
if (imageSource == "image1.png"){
imageSource = "image2.png";
}
else if (imageSource == "image2.png"){
imageSource = "image3.png";
}
else {
imageSource = "image1.png";
}
}
This should make the image rotate between 3 different image files (image1.png, image2.png and image3.png). Bear in mind this will only work if you have a finite number of image files that you want to rotate through, otherwise you'd be better off using counters.
Hope this helps.
Check the below code if you make it as a cyclic:
JS
var imgArray = ["image1.png", "image2.png", "image3.png"];
function changeImage(){
var img = document.getElementById("image").src.split("/"),
src = img[img.length-1];
idx = imgArray.indexOf(src);
if(idx == imgArray.length - 1) {
idx = 0;
}
else{
idx++;
}
document.getElementById("image").src = imgArray[idx];
}
html
<button onclick=changeImage();>Click me!</button>
function changeImage(){
document.getElementById("image").attr("src","image2.png");
}

Make a new image appear by clicking on the previous image

I want to write a code in which when you click on an image another image appears. After that when you click on the new image, another one appears, and so on.
I wrote this code which works for the first image. I can't figure out how to define the appeared images as inputs.
var i = 1
function addimage() {
var img = document.createElement("img");
img.src = "images/d" + i + ".jpg";
document.body.appendChild(img);
}
function counter() {
i = i + 1
}
<input type="image" src="images/d1.jpg" onclick="addimage(); counter();">
Attach an onclick function to the new image, with the same code as in your input tag:
var i = 1
function imageClick() {
if (! this.alreadyClicked)
{
addimage();
counter();
this.alreadyClicked = true;
}
}
function addimage() {
var img = document.createElement("img");
img.src = "http://placehold.it/" + (200 + i);
img.onclick = imageClick;
document.body.appendChild(img);
}
function counter() {
i = i + 1
}
<input type="image" src="http://placehold.it/200" onclick="imageClick();">
To add an event handler to an element, there are three methods; only use one of them:
=> With an HTML attribute. I wouldn't recommend this method because it mixes JS with HTML and isn't practical in the long run.
<img id="firstImage" src="something.png" onclick="myListener(event);" />
=> With the element's attribute in JS. This only works if you have a single event to bind to that element, so I avoid using it.
var firstImage = document.getElementById('firstImage');
firstImage.onclick = myListener;
=> By binding it with JavaScript. This method has been standardized and works in all browsers since IE9, so there's no reason not to use it anymore.
var firstImage = document.getElementById('firstImage');
firstImage.addEventListener("click", myListener);
Off course, myListener needs to be a function, and it will receive the event as its first argument.
In your case, you probably don't want to add another image when you click on any image that isn't currently the last. So when a user clicks on the last image, you want to add a new image and stop listening for clicks on the current one.
var i = 1;
function addNextImage(e) {
// remove the listener from the current image
e.target.removeEventListener("click", addNextImage);
// create a new image and bind the listener to it
var img = document.createElement("img");
img.src = "http://placehold.it/" + (200 + i);
img.addEventListener("click", addNextImage);
document.body.appendChild(img);
// increment the counter variable
i = i + 1;
}
var firstImage = document.getElementById("firstImage");
firstImage.addEventListener("click", addNextImage);
Try on JSFiddle
On a side note: while JavaScript does support omitting some semi-columns it's considered a better practice to put them, and it will avoid small mistakes.

How to stop a javascript function from within another function?

I'm developing a simple slideshow system.
I've got the slideshow wrapped in a hidden div, which is shown when a thumbnail from the gallery is clicked.
The slideshow works through a function called commence(), which is executed when the play button is clicked.
At the moment I've got it set to hide to whole div again when stop is clicked, but I would like to keep the div shown, simply stop the slideshow, in other words, stop the commence() function.
Can anyone tell me how to do this?
Here is my JS:
function commence() {
hidden = document.getElementById("hidden");
hidden.style.display = 'block';
pause = document.getElementById("pause");
pause.style.display = 'block';
play = document.getElementById("play");
play.style.display = 'none';
pic = document.getElementById("picbox"); // Assign var pic to the html element.
imgs = []; // Assign images as values and indexes to imgs array.
/* --------------------------- IMAGE URLS FOR IMGS ARRAY -------------------------*/
imgs[0] = "/snakelane/assets/images/thumb/_1.jpg"; imgs[10] = "/snakelane/assets/images/thumb/_19.jpg";
imgs[1] = "/snakelane/assets/images/thumb/_2.jpg"; imgs[11] = "/snakelane/assets/images/thumb/_20.jpg";
imgs[2] = "/snakelane/assets/images/thumb/_3.jpg"; imgs[12] = "/snakelane/assets/images/thumb/_21.jpg";
imgs[3] = "/snakelane/assets/images/thumb/_4.jpg"; imgs[13] = "/snakelane/assets/images/thumb/_22.jpg";
imgs[4] = "/snakelane/assets/images/thumb/_5.jpg"; imgs[14] = "/snakelane/assets/images/thumb/_23.jpg";
imgs[5] = "/snakelane/assets/images/thumb/_6.jpg"; imgs[15] = "/snakelane/assets/images/thumb/_24.jpg";
imgs[6] = "/snakelane/assets/images/thumb/_7.jpg"; imgs[16] = "/snakelane/assets/images/thumb/_25.jpg";
imgs[7] = "/snakelane/assets/images/thumb/_8.jpg"; imgs[17] = "/snakelane/assets/images/thumb/_26.jpg";
imgs[8] = "/snakelane/assets/images/thumb/_9.jpg"; imgs[18] = "/snakelane/assets/images/thumb/_27.jpg";
imgs[9] = "/snakelane/assets/images/thumb/_10.jpg"; imgs[19] = "/snakelane/assets/images/thumb/_28.jpg";
/* -----------------------------------------------------------------------------------------------------*/
var preload = []; // New array to hold the 'new' images.
for(i = 0 ; i < imgs.length; i++) // Loop through imgs array
{
preload[i] = new Image(); // Loop preload array and declare current index as a new image object.
preload[i].src = imgs[i]; // Fill preload array with the images being looped from ims array.
}
i = 0; // Reset counter to 0.
rotate(); // Execute rotate function to create slideshow effect.
}
// Function to perform change between pictures.
function rotate() {
pic.src = imgs[i]; // Change html element source to looping images
(i === (imgs.length -1))?(i=0) : (i++); // counter equals imgs array length -1.
setTimeout( rotate, 4000); // Sets the time between picture changes. (5000 milliseconds).
}
function init() {
[].forEach.call(document.querySelectorAll('.pic'), function(el) {
el.addEventListener('click', changeSource);
});
function changeSource() {
hidden = document.getElementById("hidden");
hidden.style.display = 'block';
newpic = this.src;
var pic = document.getElementById("picbox");
pic.src = newpic;
}
}
document.addEventListener("DOMContentLoaded", init, false);
function stopSlide() {
var hidden = document.getElementById("hidden");
hidden.style.visibility = 'hidden';
pause.style.display = 'none';
var play = document.getElementById("play");
play.style.display = 'block';
}
The pause and play statements are not relevant to my question, they simply hide the play button and show the pause button if the slideshow is running, and vice versa.
It looks to me like you actually want to stop the rotate() function, rather then commence, since rotate is what is actually changing the images (ie running the slideshow).
There are two ways. The first, like thriqon posted, is to use the clearTimeout function. However I'd recommend doing it like this:
// somewhere in global space
var rotateTimeout;
// in commence
rotateTimeout = window.setInterval(rotate,4000); // this will tell the browser to call rotate every 4 seconds, saving the ID of the interval into rotateTimeout
// in stopSlide
window.clearInterval(rotateTimeout); // this will tell the browser to clear, or stop running, the interval.
The second, which is a bit messier, is to use a sentinel.
// somewhere in global space
var running;
// in commence
running = true;
rotate();
// in stopSlide
running = false;
// in rotate
if (running) {
setTimeout(rotate,4000);
}
You want to use window.clearTimeout using the id you get by call window.setTimeout.
But you should also consider switching to window.setInterval, which gives you an function call every 4 seconds (and not 4 seconds after the last call), the not-needing of repeated calls to re-set the timeout and a better handling of missed events.
See this jsFiddle: http://jsfiddle.net/D3kMG/ for an example on how to use these functions for a simple counter.
As mentioned by #thriqon you will want to use window.clearTimeout. To do this you need to save a "global" reference to the id returned by window.setTimeout, as follows:
var timeoutID;
//... function declarations
function rotate() {
//...
timeoutID = setTimeout( rotate, 4000);
}
Then in your stopSlide function you'll simply call clearTimout( timeoutID ) to stop the rotation.

Categories