Reputation: 3
I have a set of buttons that each add an image on the next click at the position of the click inside a specific div. However, I'm facing a problem that after I've clicked a button every click will add the image until I hit a different button. How can I make it so clicking the button only allows the onmousedown function to be called once?
Here is what I have:
function makeSnow() {
document.body.style.backgroundColor = "red";
document.getElementById("canvas").onmousedown = function() {
var x = event.clientX;
var y = event.clientY;
var pic = document.getElementById("snowballAppear");
pic.style.display = '';
pic.style.position = 'absolute';
pic.style.left = x - 50 + 'px';
pic.style.top = y - 50 + 'px';
document.body.style.backgroundColor = 'blue';
};
};
function makeCat() {
document.body.style.backgroundColor = "red";
document.getElementById("canvas").onmousedown = function() {
var x = event.clientX;
var y = event.clientY;
var pic = document.getElementById("catAppear");
pic.style.display = '';
pic.style.position = 'absolute';
pic.style.left = x - 50 + 'px';
pic.style.top = y - 50 + 'px';
document.body.style.backgroundColor = 'blue';
};
};
function makeDog() {
document.body.style.backgroundColor = "red";
document.getElementById("canvas").onmousedown = function() {
var x = event.clientX;
var y = event.clientY;
var pic = document.getElementById("dogAppear");
pic.style.display = '';
pic.style.position = 'absolute';
pic.style.left = x - 50 + 'px';
pic.style.top = y - 50 + 'px';
document.body.style.backgroundColor = 'blue';
};
};
<div id="container" class "container">
<div id='canvas' style="background-color: green; width: 300px; height: 300px;">
</div>
<ul>
<button onClick="makeSnow()">
<li>snow</li>
</button>
<button onClick="makeCat()">
<li>cat</li>
</button>
<button onClick="makeDog()">
<li>dog</li>
</button>
</ul>
<div class "picture">
<img alt="snowballAppear" id="snowballAppear" style="display: none; width: 100px; height: 100px;" src="http://vignette3.wikia.nocookie.net/pottermore/images/9/99/Snowball-lrg.png/revision/latest?cb=20130412122815" />
</div>
<div class "picture">
<img alt="catAppear" id="catAppear" style="display: none; width: 100px; height: 100px;" src="https://images.pexels.com/photos/104827/cat-pet-animal-domestic-104827.jpeg?h=350&auto=compress&cs=tinysrgb" />
</div>
<div class "picture">
<img alt="dogAppear" id="dogAppear" style="display: none; width: 100px; height: 100px;" src="https://images.pexels.com/photos/39317/chihuahua-dog-puppy-cute-39317.jpeg?h=350&auto=compress&cs=tinysrgb" />
</div>
</div>
Upvotes: 0
Views: 500
Reputation:
There are three ways to bind an event to an element in JavaScript, the old fashionned spaghetti style that is much hated these days, the intermediate style with property affectation that is not so bad but not really a good practice, and the trendy style that is using addEventListener
.
Old fashionned spaghetti style :
function sayHello() {
console.log("hello");
}
<button onclick="sayHello()">Say hello</button>
Intermediate style with property affectation :
var btn = document.getElementById("btn");
btn.onclick = sayHello;
function sayHello() {
console.log("hello");
}
<button id="btn">Say hello</button>
Trendy style with addEventListener
:
var btn = document.getElementById("btn");
btn.addEventListener("click", sayHello);
function sayHello() {
console.log("hello");
}
<button id="btn">Say hello</button>
The last two styles avoid the HTML+JS soup. This is considered a good practice that helps to produce "unobstrusive JavaScript" (Wikipedia to the rescue). That being said, the third approach is often the best option in that it makes it easy to deal with multiple listeners :
var btn = document.getElementById("btn");
btn.addEventListener("click", sayHello);
btn.addEventListener("click", sayGoodbye);
function sayHello() {
console.log("hello");
}
function sayGoodbye() {
console.log("goodbye");
}
<button id="btn">Say hello and goodbye</button>
Now to solve the "one click, one picture" problem you need to stop listening whenever the user clicks on the button. To do this you can either reset the onclick
property, or use a new function called removeEventListener
. One snippet for both options :
var btn = document.getElementById("btn");
btn.onclick = sayHello;
btn.addEventListener("click", sayGoodbye);
function sayHello() {
console.log("hello");
btn.onclick = null;
}
function sayGoodbye() {
console.log("goodbye");
btn.removeEventListener("click", sayGoodbye);
}
<button id="btn">Say hello and goodbye once</button>
Another possibility would be to use a global variable combined with an if
statement. Not a best practice, but I believe it's worth mentionning it :
var shouldSayHello = false;
var masterBtn = document.getElementById("master-btn");
var slaveBtn = document.getElementById("slave-btn");
masterBtn.onclick = unlock;
slaveBtn.onclick = sayHello;
slaveBtn.style.color = "gray";
function unlock() {
shouldSayHello = true;
slaveBtn.style.color = "black";
}
function sayHello() {
if (shouldSayHello) {
console.log("hello");
shouldSayHello = false;
slaveBtn.style.color = "gray";
}
}
<button id="master-btn">Unlock</button>
<button id="slave-btn">Say hello once</button>
All this to finally answer the actual question. Note that you have to clone the hidden image element with the cloneNode
function in order to add multiple cats to the canvas (we only need cats for the demo) :
var catBtn = document.getElementById("cat-btn");
catBtn.addEventListener("click", prepareCatLanding);
function prepareCatLanding() {
var canvas = document.getElementById("canvas");
document.body.style.backgroundColor = "red";
canvas.addEventListener("mousedown", appendCat);
};
function appendCat() {
var x = event.clientX;
var y = event.clientY;
var src = document.getElementById("catAppear");
this.removeEventListener("mousedown", appendCat);
pic = src.cloneNode();
pic.id = '';
pic.style.display = '';
pic.style.position = 'absolute';
pic.style.left = x - 50 + 'px';
pic.style.top = y - 50 + 'px';
src.parentNode.appendChild(pic);
document.body.style.backgroundColor = 'blue';
}
<div id="container" class="container">
<ul>
<li><button id="cat-btn">cat</button></li>
</ul>
<div id="canvas" style="background-color: green; width: 300px; height: 300px;">
</div>
<div class="picture">
<img alt="catAppear" id="catAppear" style="display: none; width: 100px; height: 100px;" src="https://images.pexels.com/photos/104827/cat-pet-animal-domestic-104827.jpeg?h=350&auto=compress&cs=tinysrgb" />
</div>
</div>
I've fixed the HTML along the way. Indeed, <button><li></li></button>
is not valid since <ul>
only accepts list items, it should be the opposite, that is <li><button></button></li>
. Moreover, class "container"
should be class="container"
.
Upvotes: 1
Reputation: 4020
At the end of your event listener, you could reset the mousedown to something else that doesn't do anything:
function makeSnow() {
document.body.style.backgroundColor = "red";
document.getElementById("canvas").onmousedown = function() {
var x = event.clientX;
var y = event.clientY;
var pic = document.getElementById("catAppear");
pic.style.display = '';
pic.style.position = 'absolute';
pic.style.left = x - 50 + 'px';
pic.style.top = y - 50 + 'px';
document.body.style.backgroundColor = 'blue';
document.getElementById("canvas").onmousedown = function() {
//do nothing;
};
};
};
And then the same for the other functions.
Upvotes: 1
Reputation: 1838
The accepted answer suggests to redefine onmousedown event handler, which would work but requires you to write superfluous code. Here is shorter version by the way =).
document.getElementById("canvas").onmousedown = null;
It seems like a simple event listener which triggers only once is a suitable solution as well.
document.getElementById("canvas").addEventListener("mousedown", functionToExecuteOnceEventOccurs, { once: true });
Take a look at docs on MDN. Pay attention to browser compatibility table though, "once" option is not that widely supported.
Upvotes: 0
Reputation: 2845
You need to replace the onmousedown
event listener with a function that does nothing, in the original onmousedown
event listener. Like this:
function makeCat() {
document.body.style.backgroundColor = "red";
document.getElementById("canvas").onmousedown = function() {
...
document.getElementById("canvas").onmousedown = () => {};
};
};
Upvotes: 2
Reputation: 3197
You can return right after image is added, add an condition to your liking, I am not sure what exacly is your problem.
if (some condition) return;
But before anything:
class "container"
and many more like it is not how you write classes in HTML, the correct notation is class="name"
Upvotes: 0