How to make onclick function execute only once?

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.

  1. Event Listener (recommended)
    • document.querySelector('.once').addEventListener('click', test);`
  2. On-event Attribute (not recommended)
    • <a href='#/' class='once'onclick='test()'>Click</a>
  3. 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:

  1. .default - a normal link registered to the click event which when triggered calls test()

  2. .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>

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>

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


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