Toggle Event Listeners - javascript

I am trying to make a function that would allow me to toggle eventListener of an element.
In the example below, I have three buttons: main, on and off. When I click on the on button, the main button becomes functional. After I click off button, the main button should not work anymore (but now it still does).
Now I can achieve a desired behavior by clicking on button for the second time, but I guess it's a bad coincidence and it's not supposed to work that way.
Maybe I should add that I would like to work this out without using jQuery or similar and it needs to be a function, because I am going to use it for a lot of buttons.
(I suspect something with scope causes the problem (clickHandler when calling the function to activate the button is not the same as the clickHandler when calling the function to disable the button), but I can't think of a way to test it.)
// buttons definitions, not important
var mainButton = document.querySelector("#mainButton");
var onButton = document.querySelector("#onButton");
var offButton = document.querySelector("#offButton");
// main function
var toggleButtons = function(toggleVal, button, element) {
var activateButton, clickHandler, disableButton;
// callback function for listener bellow
clickHandler = function() {
document.querySelector(element).classList.toggle("yellow");
};
activateButton = function() {
button.addEventListener("click", clickHandler);
};
disableButton = function() {
button.removeEventListener("click", clickHandler);
};
// when first argument is 1, make the button functional, otherwise disable its functionality
if (toggleVal === 1) {
activateButton();
} else {
disableButton();
}
};
// when onButton is clicked, call main function with arguments
// this works
onButton.addEventListener("click", function() {
toggleButtons(1, mainButton, "body");
});
// this fails to disable the button
offButton.addEventListener("click", function() {
toggleButtons(0, mainButton);
});
.yellow {
background-color: yellow;
}
<button type="button" id="mainButton">mainButton
</button>
<button type="button" id="onButton">onButton
</button>
<button type="button" id="offButton">offButton
</button>
<p>mainButton: toggles background color on click
</p>
<p>onButton: turns on mainButtons's functionality</p>
<p>offButton: supposed to turn off mainButton's functionality</p>

var mainButton = document.querySelector("#mainButton");
var onButton = document.querySelector("#onButton");
var offButon = document.querySelector("#offButton");
var element; // declare the element here and change it from toggleButtons when needed.
function clickHandler() {
document.querySelector(element).classList.toggle('yellow');
}
function activateButton(button) { // You missed this part
button.addEventListener('click', clickHandler);
}
function disableButton(button) { // You missed this part
button.removeEventListener('click', clickHandler);
}
function toggleButtons(value, button) {
if (value === 1) {
activateButton(button); // You missed this part
} else {
disableButton(button); // You missed this part
}
};
onButton.addEventListener('click', function() {
element = 'body'; // you can change it to some other element
toggleButtons(1, mainButton);
});
offButton.addEventListener('click', function() {
element = 'body'; // you can change it to some other element
toggleButtons(0, mainButton);
});

Below code helps to toggle between two functions from an eventListener:
var playmusic=false;
function playSound() {
const audio = document.querySelector(`audio[data-key="${event.keyCode}"]`)
audio.currentTime = 0
audio.play()
playmusic=true;
}
function stopSound() {
const audio = document.querySelector(`audio[data-key="${event.keyCode}"]`)
audio.pause()
playmusic=false;
}
window.addEventListener('keydown',
function(){playmusic?stopSound():playSound()} )

Related

How to remove a single function from click event listener that has multiple functions, using Javascript?

Using Javascript, how do you remove a single function from a "click" event listener, after the first click event, when there are multiple functions being used on the element with the "click" event listener? Here, after the first click, only toggleView() should remain and renderList() should be removed.
const button = document.getElementById("view_button");
button.addEventListener("click", () => {
toggleView(); // want to keep this indefinitely
renderList(); // want to remove this after the first click
button.removeEventListener("click", renderList);
});
You need to add both separately, and specify { once: true } on the one you want removed after first execution.
See MDN:
once
A boolean value indicating that the listener should be invoked at most once after being added. If true, the listener would be automatically removed when invoked.
function toggleView() {
console.log('toggleView');
}
function renderList(evt) {
console.log('renderList');
}
const button = document.getElementById("view_button");
button.addEventListener("click", toggleView);
button.addEventListener("click", renderList, { once: true });
<button type="button" id="view_button">Click</button>
You can add two event listeners and remove the one
function toggleView() {
console.log('toggleView');
}
function renderList(evt) {
evt.currentTarget.removeEventListener("click", renderList);
console.log('renderList');
}
const button = document.getElementById("view_button");
button.addEventListener("click", toggleView);
button.addEventListener("click", renderList);
<button type="button" id="view_button">Click</button>
or you can just add logic to determine if the function should be run.
function toggleView() {
console.log('toggleView');
}
function renderList() {
console.log('renderList');
}
const button = document.getElementById("view_button");
button.addEventListener("click", () => {
toggleView();
if (!button.dataset.clicked) {
renderList();
button.dataset.clicked = '1';
}
});
<button type="button" id="view_button">Click</button>
I would use a closure here to keep track of if the item has been clicked.
const button = document.getElementById("view_button");
function toggleView() {
console.log('Toggle View');
}
function renderList() {
console.log('Render List');
}
function clickHandler() {
let hasBeenClicked = false;
return function () {
toggleView();
if (!hasBeenClicked) {
renderList();
hasBeenClicked = true;
}
};
}
button.addEventListener("click", clickHandler());
<button id="view_button" type="button">View Button</button>

Javascript object methods evaluate functions

first of all, I'm new to javascript.
my question is how can I add an event listener to the button and call the function from the myObj script. I tried to google but I don't know what is the keyword for that. thank you
<div id="my-btn"></div>
<script>
myObj.button('my-btn',{
onClick: function() {
alert('Button is clicked !');
},
onCancel: function() {
alert('You cancel the process !');
}
});
</script>
and my object
var myObj = {
button: function(btnId, methods)
{
var btn = document.getElementById(btnId);
for (var method in methods)
{
if (method.toLowerCase() == 'onclick')
{
//btn.addEventListener('click', function(e) {
//}
// i want to add listener
// and call the function "onClick"
}
}
// render button
btn.innerHTML = '<input type="button" value="My Button"></button>';
}
}
thank you for your advice.
Here's one way.
<html>
<head></head>
<body>
<div id="my-btn"></div>
</body>
<script>
const myObj = {
button: (btnId, methods) => {
const btn = document.getElementById(btnId);
for (let method in methods) {
const nameLower = method.toLowerCase();
if (nameLower.startsWith('on')) {
btn.addEventListener(nameLower.substr(2), function(e) {
methods[method]();
});
}
}
// render button
btn.innerHTML = '<input type="button" value="My Button"></button>';
}
};
myObj.button('my-btn',{
onClick: () => alert('Button is clicked !'),
onCancel: () => alert('You cancel the process !')
});
</script>
</html>
We can map the function names to their events by converting to lowercase and stripping off the "on" prefix. So onClick becomes click. You could simplify things by just using the standard event names in your call to myObj.button.
Start by iterating over the functions, map the name and add the event listener. Inside the event listener all we do is call the function provided in the arguments.

Kill, abort, stop, cancel a previous call/queue to a javascript function

I have a function which will take some time to run on click event.
Following is merely an example and setTimeout is there only to simulate time it may take to run it. How can I ensure when a user click on an item any previous running function(s) is(are) cancelled and only the latest onclick function is fired?
i.e. if a user clicked on it 10 times. I want to only execute the only the 10th click not the 9 clicks before.
I am hoping for a pure/vanilla js solution... NOT jQuery
(function () {
var nav = document.querySelector('.nav__toggle');
var toggleState = function (elem, one, two) {
var elem = document.querySelector(elem);
elem.setAttribute('data-state', elem.getAttribute('data-state') === one ? two : one);
};
nav.onclick = function (e) {
setTimeout(function(){
toggleState('.nav ul', 'closed', 'open');
}, 5000);
e.preventDefault();
};
})();
fiddle: http://jsfiddle.net/6p94p48m/
You need to debounce your click handler.
var button = document.getElementById("debounced");
var clickHandler = function() {
alert('click handler');
}
var debounce = function(f, debounceTimeout) {
var to;
return function() {
clearTimeout(to);
to = setTimeout(f, debounceTimeout);
}
}
button.addEventListener('click', debounce(clickHandler, 5000));
<button id="debounced" href="#">debounced</button>
Or use underscore/lodash https://lodash.com/docs#debounce

add1 does not exist in DOM How to Add?

I am having an issue with java-script and an HTML form.
I have a form and next to the form is a button called "add" when I click add the second form appears. Next to form 2 is another button called add1, when I click this button I am wanting the third form to display. For some reason only the first add button is working.
Below is the code I have so far:
<style type="text/css">
#newservicesetup1, #newservicesetup2 {
display:none;
}
</style>
<script type="text/javascript">
function showform(theform) {
var showHides = new Array('newservicesetup1','newservicesetup2');
for (i=0;i<showHides.length;i++) {
document.getElementById(showHides[i]).style.display=
(document.getElementById(showHides[i]).id == theform) ? 'block' : 'none';
}
}
function loadBehaviors () {
if (document.getElementById) {
document.getElementById('add').onclick = function() { showform('newservicesetup1'); }
document.getElementById('add1').onclick = function() { showform('newservicesetup2'); }
}
}
window.onload = loadBehaviors;
</script>
Try adding a semicolon to the end of the assignments:
function loadBehaviors () {
if (document.getElementById) {
document.getElementById('add').onclick = function() { showform('newservicesetup1'); };
document.getElementById('add1').onclick = function() { showform('newservicesetup2'); };
}
}
You can check your Javascript for syntax using Online Javascript Lint.
why not just
document.getElementById('add').onclick = function() {
document.getElementById('newservicesetup1').style.display = 'block';
}
document.getElementById('add1').onclick = function() {
document.getElementById('newservicesetup1').style.display = 'block';
}
that will show the correct forms when you click the appropriate button. if you want them to disappear when clicking again, you will only need a slight modification
When loadBehaviors() is called, add1 does not exist in the DOM yet. Bind to the event handler after you add it to the DOM.

Changing HTML on click in D3.js disables doubleclick [duplicate]

I've toggled click event to a node and I want to toggle a dbclick event to it as well. However it only triggers the click event when I dbclick on it.
So How do I set both events at the same time?
You have to do your "own" doubleclick detection
Something like that could work:
var clickedOnce = false;
var timer;
$("#test").bind("click", function(){
if (clickedOnce) {
run_on_double_click();
} else {
timer = setTimeout(function() {
run_on_simple_click(parameter);
}, 150);
clickedOnce = true;
}
});
function run_on_simple_click(parameter) {
alert(parameter);
alert("simpleclick");
clickedOnce = false;
}
function run_on_double_click() {
clickedOnce = false;
clearTimeout(timer);
alert("doubleclick");
}
Here is a working JSFiddle
For more information about what delay you should use for your timer, have a look here : How to use both onclick and ondblclick on an element?
$("#test-id").bind("click dblclick", function(){alert("hello")});
Works for both click and dblclick
EDIT --
I think its not possible. I was trying something like this.
$("#test").bind({
dblclick: function(){alert("Hii")},
mousedown: function(){alert("hello")}
});
But its not possible to reach double click without going through single click. I tried mouse down but it does not give any solution.
I pretty much used the same logic as Jeremy D.
However, in my case, it was more neat to solve this thing with anonymous functions, and a little slower double click timeout:
dblclick_timer = false
.on("click", function(d) {
// if double click timer is active, this click is the double click
if ( dblclick_timer )
{
clearTimeout(dblclick_timer)
dblclick_timer = false
// double click code code comes here
console.log("double click fired")
}
// otherwise, what to do after single click (double click has timed out)
else dblclick_timer = setTimeout( function(){
dblclick_timer = false
// single click code code comes here
console.log("single click fired")
}, 250)
})
you need to track double click and if its not a double click perform click action.
Try this
<p id="demo"></p>
<button id='btn'>Click and DoubleClick</button>
<script>
var doubleclick =false;
var clicktimeoutid = 0;
var dblclicktimeoutid = 0;
var clickcheck = function(e){
if(!clicktimeoutid)
clicktimeoutid = setTimeout(function(){
if(!doubleclick)
performclick(e);
clicktimeoutid =0;
},300);
}
var performclick =function(e){
document.getElementById("demo").innerHTML += 'click';
}
var performdblclick = function(e)
{
doubleclick = true;
document.getElementById("demo").innerHTML += 'dblclick';
dblclicktimeoutid = setTimeout(function(){doubleclick = false},800);
};
document.getElementById("btn").ondblclick = performdblclick;
document.getElementById("btn").onclick=clickcheck;
</script>
a slightly different approach - The actual click comparison happens later in the timeOut function, after a preset interval... till then we simply keep tab on the flags.
& with some simple modifications (click-counter instead of flags) it can also be extended to any number of rapid successive clicks (triple click, et al), limited by practicality.
var clicked = false,
dblClicked = false,
clickTimer;
function onClick(param){
console.log('Node clicked. param - ',param);
};
function onDoubleClick(param){
console.log('Node Double clicked. param - ',param);
};
function clickCheck(param){
if (!clicked){
clicked = true;
clickTimer = setTimeout(function(){
if(dblClicked){
onDoubleClick(param);
}
else if(clicked){
onClick(param);
}
clicked = false;
dblClicked = false;
clearTimeout(clickTimer);
},150);
} else {
dblClicked = true;
}
};

Categories

Resources