How to make onclick function execute only once? [duplicate] - javascript

This question already has answers here:
How to pass parameter to function using in addEventListener?
(4 answers)
What is the difference between a function call and function reference?
(6 answers)
Closed 3 months ago.
I have this code for Google analytics on a button. I need it to be executed only once, so that the user can't change statistics by pressing the button many times. I tried solutions from similar topics, but they don't work. Please help. This is my code.
<script>
function klikaj(i) {
gtag('event', 'first-4', {
'event_category' : 'cat-4',
'event_label' : 'site'
});
}
document.body.addEventListener("click", klikaj(i), {once:true})
</script>
<div id="thumb0" class="thumbs" onclick="klikaj('rad1')">My button</div>

Remove onclick attribute on your button and register listener via JavaScript, as you tried to do:
<div id="thumb0" class="thumbs"
style="border: 1px solid; cursor: pointer; float: left">
My button
</div>
<script>
function klikaj(i) {
console.log(i);
}
document.getElementById('thumb0')
.addEventListener("click", function(event) {
klikaj('rad1');
}, {once: true});
</script>
If your browser doesn't support { once: true } option, you can remove event listener manually:
<div id="thumb0" class="thumbs"
style="border: 1px solid;cursor: pointer;float:left">
My button
</div>
<script>
function klikaj(i) {
console.log(i);
}
function onClick(event) {
klikaj('rad1');
document
.getElementById('thumb0')
.removeEventListener("click", onClick);
}
document
.getElementById('thumb0')
.addEventListener("click", onClick);
</script>

you could use removeAttribute() like this: document.getElementById('thumb0').removeAttribute("onclick");
or you could let the function return false like this: document.getElementById('thumb0').onclick = ()=> false

I would recommend setting a variable and checking its value.
<script>
var clicked = false;
function klikaj(i) {
if (clicked === false) {
gtag('event', 'first-4', {
'event_category' : 'cat-4',
'event_label' : 'site'
});
}
clicked = true;
}
...
</script>
Or removing the onclick event as suggested by others,
<script>
function klikaj(i) {
gtag('event', 'first-4', {
'event_category' : 'cat-4',
'event_label' : 'site'
});
document.getElementById('thumb0).onclick = undefined;
}
...
</script>
Note that once: true is unfortunately not supported in IE and Edge. See https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener

Event Handlers & Listeners
There are three ways* to register an event to an element. The following examples show how to register the click event to a link with the class .once** which calls the function test() when triggered.
Event Listener (recommended)
document.querySelector('.once').addEventListener('click', test);`
On-event Attribute (not recommended)
<a href='#/' class='once'onclick='test()'>Click</a>
On-event Property
document.querySelector('.once').onclick = test;`
*See DOM on-event handlers for details
** .once class is not relevant for #2
Issues
The OP (Original Post) has an event listener (see #1 above) registering a click event to the <body> tag and an on-event attribute (see #2 above) registering the click event to a <div>. Each one calls a function (aka callback function) named klikaj() which is redundant. Clicking the body (which is normally everywhere) isn't useful when you intend to have the user click a div. Should the user click anywhere but the div, klikaj() will be called. Should the user click the div, klikaj() will be called twice. I suggest that you remove both event handlers and replace them with this:
A.
document.getElementById('thumb0').addEventListener("click", klikaj);
Note that klikaj has no parenthesis () because the browser interprets () as to run the function now instead of when the user triggers the registered event (see #1 and #3 above). Should an event handler have additional statements and/or callback functions then an anonymous function should be wrapped around it and normal syntax applies:
B.
document.getElementById('thumb0').addEventListener("click", function(event) {
klikaj();
console.log('clicked');
});
A cleaner alternative is to add extra lines in the definition of the callback function instead and registering events like #A.
Solution
Simply add the following statement as the last line of klikaj():
this.style.pointerEvents = "none";
That will render the clicked tag unclickable. Applied to OP code it should be like this:
<div id="thumb0" class="thumbs">Thumb 0</div>
<script>
function klikaj(event) {
gtag('event', 'first-4', {
'event_category' : 'cat-4',
'event_label' : 'site'
});
this.style.pointerEvents = "none";
}
document.getElementById('thumb0').addEventListener("click", klikaj);
</script>
Demo
The following demo has two links:
.default - a normal link registered to the click event which when
triggered calls test()
.once - a link registered to the click event which when triggered
calls test() and renders the link unclickable.
function test() {
console.log('test');
}
document.querySelector('.default').onclick = function(e) {
test();
}
document.querySelector('.once').onclick = function(e) {
test();
this.style.pointerEvents = 'none';
}
<a href='#/' class='default'>Default</a><br>
<a href='#/' class='once'>Once</a>

There is a problem with the way you are trying to attach your handler function.
The function klikaj(i) returns undefined so you are attaching undefined to the button. If you want to execute klikaj(i) when the button is clicked, put it inside a closure like this:
const button = document.querySelector('button')
const i = 10
function klikaj(i) {console.log('clicked once')}
button.addEventListener('click', () => { klikaj(i) }, {once: true})
<button>Hello world</button>
If the browser does not support the {once: true} you can simulate it using:
const button = document.querySelector('button')
const i = 10
function klikaj(i) {console.log("clicked once")}
function clickOnceHandler(event) {
klikaj(i)
event.currentTarget.removeEventListener('click', clickOnceHandler)
}
button.addEventListener('click', clickOnceHandler)
<button>Hello world</button>

Just use a flag variable and set it upon the first execution:
var handlerExecuted = false;
function clickHandler() {
if (!handlerExecuted) {
console.log("call gtag() here");
handlerExecuted = true;
} else {
console.log("not calling gtag() function");
}
}
document
.getElementById("thumb0")
.addEventListener("click", clickHandler);
<div id="thumb0" class="thumbs">My button</div>
An advance variation that uses closures and could be used on multiple buttons:
function clickHandlerFactory() {
var handlerExecuted = false;
return function() {
if (!handlerExecuted) {
console.log("call gtag() here");
handlerExecuted = true;
} else {
console.log("not calling gtag() function");
}
}
}
[...document.querySelectorAll(".thumbs")].forEach(function(el) {
el.addEventListener("click", clickHandlerFactory());
});
<div id="thumb0" class="thumbs">Button 1</div>
<div id="thumb1" class="thumbs">Button 2</div>

If you want the function to be called only when user clicks the button, you will have remove the click event listener from the body.
To fire your gtag function only once you can change the function definition of klikaj inside the function body itself. After the first call gtag will never be called.
The below code works fine.
<script>
function klikaj(i) {
gtag('event', 'first-4', {
'event_category' : 'cat-4',
'event_label' : 'site'
});
klikaj = function() {};
}
</script>
<div id="thumb0" class="thumbs" onclick="klikaj('rad1')">
My button
</div>

Related

How to pass arguments to the event listener's function so that there would be no duplicate event listeners?

Currently, I use the following solution:
<button onclick="initiate('ok2')" id="btn1">Initiate</button>
<button id="btn2">Send data</button>
function initiate(ok) {
document.getElementById("btn2").addEventListener("click", receiveData);
}
function receiveData(event) {
console.log(event);
}
The benefit of this approach lies in the named function receiveData, which is recognized as the same function and is not added repeatedly.
Steps to reproduce:
Press the 'Initiate' button multiple times
Press 'Send data'
Result: console log is printed only once
I want to utilize the same approach, but add an attribute to the function. I tried the bind approach, but the event listener is added multiple times. As a result, the console log is also printed multiple times.
Example:
function initiate(ok) {
document.getElementById("btn2").addEventListener("click", receiveData.bind(null, ok));
}
function receiveData(event, ok) {
console.log(event);
console.log(ok);
}
Is it possible to pass an argument to a function and not create duplicate event listeners? Ideally, it would be preferred not to delete event listeners, like in the current solution.
Here is my version with the recommended ways of delegating and setting and getting data attribute
A user cannot click what is not visible so no need to initiate the button, just unhide it
document.addEventListener("click", function(e) {
let btn = e.target
if (btn.matches("#btn1")) {
let targetBTN = document.getElementById(btn.dataset.target);
targetBTN.hidden = false;
} else if (btn.matches("#btn2")) {
console.log(btn.dataset.field);
}
});
<button id="btn1" data-target="btn2">Initiate</button>
<button id="btn2" data-field="ok2" hidden>Send data</button>
// when the window loads add a click handler to the button of choice
window.addEventListener('load', (event) => {
console.log('page is now loaded');
document.getElementById("btn2").addEventListener("click", receiveData)
});
function receiveData(event) {
console.log(event);
}
or as suggested in comments, add the click handler inline.
You need to tel it if it is inited or not..
let data = "";
let init = true;
function initiate(ok) {
data = ok
if(init ){
document.getElementById("btn2")
.addEventListener("click", receiveData);
init = false
}
}
function receiveData(event) {
console.log( data );
}
<button onclick="initiate('ok2')" id="btn1">Initiate</button>
<button id="btn2">Send data</button>
It looks like the one goal is to only allow the second button to be able to be used when the first button is clicked.
So, I attached an event listener to the document. Then used data attributes on the buttons to determine if the start button can be used or not. And just for display I used CSS to hide the start button if its not allowed to be used just yet
document.addEventListener("click",function(e){
let btn = e.target
if(btn.matches(".btn-start")){
let targetBTN = document.querySelector(`[data-id='${btn.dataset.target}']`)
targetBTN.setAttribute("data-initiated","true");
}
else if(btn.dataset.initiated == "true"){
console.log(btn.dataset.field);
}
});
[data-initiated="false"]{
display:none
}
[data-initiated="true"]{
display:inline-block
}
<button data-target="send2" class="btn-start">Initiate</button>
<button data-initiated="false" data-field="ok2" data-id="send2" class="btn-send">Send data</button>

How to add two onclick method in one button? [duplicate]

Is there any way to use the onclick html attribute to call more than one JavaScript function?
onclick="doSomething();doSomethingElse();"
But really, you're better off not using onclick at all and attaching the event handler to the DOM node through your Javascript code. This is known as unobtrusive javascript.
A link with 1 function defined
Click me To fire some functions
Firing multiple functions from someFunc()
function someFunc() {
showAlert();
validate();
anotherFunction();
YetAnotherFunction();
}
This is the code required if you're using only JavaScript and not jQuery
var el = document.getElementById("id");
el.addEventListener("click", function(){alert("click1 triggered")}, false);
el.addEventListener("click", function(){alert("click2 triggered")}, false);
I would use the element.addEventListener method to link it to a function. From that function you can call multiple functions.
The advantage I see in binding an event to a single function and then calling multiple functions is that you can perform some error checking, have some if else statements so that some functions only get called if certain criteria are met.
Sure, simply bind multiple listeners to it.
Short cutting with jQuery
$("#id").bind("click", function() {
alert("Event 1");
});
$(".foo").bind("click", function() {
alert("Foo class");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="foo" id="id">Click</div>
ES6 React
<MenuItem
onClick={() => {
this.props.toggleTheme();
this.handleMenuClose();
}}
>
var btn = document.querySelector('#twofuns');
btn.addEventListener('click',method1);
btn.addEventListener('click',method2);
function method2(){
console.log("Method 2");
}
function method1(){
console.log("Method 1");
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Pramod Kharade-Javascript</title>
</head>
<body>
<button id="twofuns">Click Me!</button>
</body>
</html>
You can achieve/call one event with one or more methods.
You can add multiple only by code even if you have the second onclick atribute in the html it gets ignored, and click2 triggered never gets printed, you could add one on action the mousedown but that is just an workaround.
So the best to do is add them by code as in:
var element = document.getElementById("multiple_onclicks");
element.addEventListener("click", function(){console.log("click3 triggered")}, false);
element.addEventListener("click", function(){console.log("click4 triggered")}, false);
<button id="multiple_onclicks" onclick='console.log("click1 triggered");' onclick='console.log("click2 triggered");' onmousedown='console.log("click mousedown triggered");' > Click me</button>
You need to take care as the events can pile up, and if you would add many events you can loose count of the order they are ran.
One addition, for maintainable JavaScript is using a named function.
This is the example of the anonymous function:
var el = document.getElementById('id');
// example using an anonymous function (not recommended):
el.addEventListener('click', function() { alert('hello world'); });
el.addEventListener('click', function() { alert('another event') });
But imagine you have a couple of them attached to that same element and want to remove one of them. It is not possible to remove a single anonymous function from that event listener.
Instead, you can use named functions:
var el = document.getElementById('id');
// create named functions:
function alertFirst() { alert('hello world'); };
function alertSecond() { alert('hello world'); };
// assign functions to the event listeners (recommended):
el.addEventListener('click', alertFirst);
el.addEventListener('click', alertSecond);
// then you could remove either one of the functions using:
el.removeEventListener('click', alertFirst);
This also keeps your code a lot easier to read and maintain. Especially if your function is larger.
React Functional components
<Button
onClick={() => {
cancelAppointment();
handlerModal();
}}
>
Cancel
</Button>
const callDouble = () =>{
increaseHandler();
addToBasket();
}
<button onClick={callDouble} > Click </button>
It's worked for me, you can call multiple functions in a single function. then call that single function.
Here is another answer that attaches the click event to the DOM node in a .js file. It has a function, callAll, that is used to call each function:
const btn = document.querySelector('.btn');
const callAll =
(...fns) =>
(...args) =>
fns.forEach(fn => fn?.(...args));
function logHello() {
console.log('hello');
}
function logBye() {
console.log('bye');
}
btn.addEventListener('click',
callAll(logHello, logBye)
);
<button type="button" class="btn">
Click me
</button>
You can compose all the functions into one and call them.Libraries like Ramdajs has a function to compose multiple functions into one.
Click me To fire some functions
or you can put the composition as a seperate function in js file and call it
const newFunction = R.compose(fn1,fn2,fn3);
Click me To fire some functions
This is alternative of brad anser - you can use comma as follows
onclick="funA(), funB(), ..."
however is better to NOT use this approach - for small projects you can use onclick only in case of one function calling (more: updated unobtrusive javascript).
function funA() {
console.log('A');
}
function funB(clickedElement) {
console.log('B: ' + clickedElement.innerText);
}
function funC(cilckEvent) {
console.log('C: ' + cilckEvent.timeStamp);
}
div {cursor:pointer}
<div onclick="funA(), funB(this), funC(event)">Click me</div>

Function is not accessible after onload event. "TypeError: {someFunctionName} is not a function"

I have written a small and simple slider with Javascript. Because I want to be sure that the slider works when I load the javascript in the footer of the page. I added an onload event and copied the whole slider application inside the event. In the HTML I unfortunately have an inline onclick element in a tag. But since I have the code inside the onload scope the onclick doesn't work anymore. My idea is not to bind the event inline in the html but directly in the javascript. That should work. But I am also interested if it is possible to do it with the inline onclick.
Question What do I have to do so that the onclick element addresses the corresponding function within the onclick function?
document.querySelector('body').onload = function() {
function init() {
// ...
}
const f2 = function() {
// ...
}
init();
/* that will work */
const anchorPrev = document.querySelector('.prev');
anchorPrev.addEventListener('click', () => {
console.log('prev');
});
/* My question */
function next() {
console.log('next')
}
};
a {
cursor: pointer;
}
<body>
<a class="next" onclick="next()">next (I'm curious to know if it works!?)</a><br/>
<a class="prev">prev (Will work)</a>
</body>
Two issues:
It's better to wait for the DOMContentLoaded event on the window object.
You're defining the function within the scope of the function, so it's not globally accessible. This means that the onclick can't see the function. Use a let variable, then set the function inside the listener callback like this:
<button onclick="log()">click me</button>
<script>
let log;
window.addEventListener('DOMContentLoaded', () => {
console.log('loaded');
log = () => console.log('clicked');
});
</script>
You can add that the onload event = function next()
JavaSript code:
document.querySelector('body').onload = function() {
const a = document.querySelector('a')
a.onclick = function next() {
event.preventDefault()
console.log('next')
}
};

toggle display in pure javascript

I am trying to toggle visibility of signup and signin boxes if sign in and sign up buttons are clicked. I am trying to use only pure javascript.
I wrote simple html and javascript as below:
<div>
<button class="signin">sign in</button><button class="signup">sign up</button>
<div class="signin-box" style="display: none;">
<form class="signin-form">
<label>username<input></label><label>password<input></label><button type="submit">signin</button>
</form>
</div>
<div class="signup-box" style="display: none;">
<form class="signup-form">
<label>username<input></label><label>password<input></label><button type="submit">signup</button>
</form>
</div>
</div>
javascript part:
var signupButton = document.getElementsByClassName('signup')[0];
var signinButton = document.getElementsByClassName('signin')[0];
var signupBox = document.getElementsByClassName('signup-box')[0];
var signipBox = document.getElementsByClassName('signin-box')[0];
console.log("box: ", signupBox, "button: ",signupButton);
var toggleVisible = function(item){
if (item.style.display === 'none'){
return item.style.display = 'block';
}else{
return item.style.display = 'none';
}
};
window.onload = function(){
signupButton.onclick = toggleVisible(signupBox);
signinButton.onclick = toggleVisible(signipBox);
};
The problem here is that the javascript toggleVisible is automatically activated even if i never clicked the buttons.
as a result, the signin-box and signup-box both gets display:block property.
How do i solve this problem?
You're calling the function, not passing it in. Just wrap your function call in an anonymous function:
signupButton.onclick = function() {
toggleVisible(signupBox);
};
If you don't care about older browsers, you can also simplify your code a little if you put your JavaScript at the bottom of the <body> tag and add a rule to your CSS:
document.querySelector('.signup').addEventListener('click', function() {
document.querySelector('.signup-box').classList.toggle('hidden');
}, false);
document.querySelector('.signin').addEventListener('click', function() {
document.querySelector('.signin-box').classList.toggle('hidden');
}, false);
And the CSS:
.hidden {
display: none;
}
I would recommend to use a standard JavaScript method addEventListener() to attached onclick event listener to the button.
It has following advantages over different solution:
You can attach an event handler to an element without overwriting existing event handlers.
You can add many event handlers of the same type to one element, i.e
two "click" events.
In your code it will look like
window.onload = function(){
signupButton.addEventListener("click", function() { toggleVisible(signupBox); });
signinButton.addEventListener("click", function() { toggleVisible(signipBox); });
};
Current code invokes toggleVisible(..) method and assigns its result to the button attribute, which is not one would expect.
signupButton.onclick = toggleVisible(signupBox);

Calling JS functions from Href

I'm curious whats the best way to call a JS function with a href link in HTML. I don't use a library and i see alot of mention about jquery using event handlers ...
But if im not using a library can it still be done or will i have to use an on click type call ?
You can use event handlers with plain javascript. No framework is required. Here's a cross browser function I use:
// add event cross browser
function addEvent(elem, event, fn) {
if (elem.addEventListener) {
elem.addEventListener(event, fn, false);
} else {
elem.attachEvent("on" + event, function() {
// set the this pointer same as addEventListener when fn is called
return(fn.call(elem, window.event));
});
}
}
And, an example of using it would be like this:
HTML:
<a id="myLink" href="#">Click ME</a>
Javascript:
var link = document.getElementById("myLink").
addEvent(link, "click", function(e) {
// process the click on the link here
});
If you don't want the default click of a link to happen, then you need to prevent the default behavior from the event handler like this:
var link = document.getElementById("myLink").
addEvent(link, "click", function(e) {
// process the click on the link here
// prevent default action of the click
if (e.preventDefault) {
e.preventDefault(); // normal browsers
} else {
e.returnValue = false; // older versions of IE (yuck)
}
});
try this
function test() { alert (''); }
<a href="#" onclick="test();" />
Basically there are two ways:
...
and
...
(in this case someFunction must return false)
I prefer the latter.

Categories