saln
saln

Reputation: 3

How do I stop onmousedown from executing again

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

Answers (7)

user1636522
user1636522

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

dev8080
dev8080

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

Pa Ye
Pa Ye

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

Hielke Walinga
Hielke Walinga

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

CodeSmith
CodeSmith

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

Celebrombore
Celebrombore

Reputation: 170

Try to use:

break; or return; at the end of each function

Upvotes: -1

Dario
Dario

Reputation: 640

You could use the return; statement in your functions to exit them.

Upvotes: 0

Related Questions