user4283097
user4283097

Reputation:

How to make sure that click functions are only performed once

When the user clicks on either .class or #id, some changes are made to the css of both divs and the value of #id increases by 1. However, when the user clicks on either one of the divs, the changes should only be made once - if the user clicks again, nothing will happen unless the page is refreshed.

$('.class, #id').one('click', function(e) {
   $('.class, #id').css({
   'background-color' : 'rgb(232,69,73)',
   'color' : '#fff',
   });
 $("#id").html(function(i, val) { return val*1+1 });
 });

Above shows the code that I am using. As you can see, I have used .one to make sure that the code is only performed once. This works, but the problem is that the user can click on .class and then click on #div which means that the code can be performed twice.

How would I edit this so that the code can only be performed once - clicking on one div means the other div can not be clicked on.

Upvotes: 1

Views: 399

Answers (3)

plalx
plalx

Reputation: 43728

I think you could use one with event delegation instead. That way you have a single handler for all targets and jQuery will automatically remove it once invoked.

$(document).one('click', '#first,#second', alert.bind(null, 'clicked'));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="first">first</button>
<button id="second">second</button>

With your code it would be:

$(document).one('click', '.class, #id', function(e) {
    //handle click
});

Here's another example showing how you could manually remove the handler after invocation in a safe way (without affecting other handlers) using a named function expression:

$('#first, #second').click(function someClickHandler(e) {
  alert('clicked!');
  
  $('#first, #second').off('click', someClickHandler);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="first">First</button>
<button id="second">Second</button>

Upvotes: 1

Danny Delott
Danny Delott

Reputation: 7008

You are setting two listeners, in fact. One on the .class and another on the #id.

This means you'll need to store a state variable and check it before performing any action.

var isClickable = true;
$('.class, #id').one('click', function(e) {
   if(isClickable){
     isClickable = false;
     $('.class, #id').css({
     'background-color' : 'rgb(232,69,73)',
     'color' : '#fff',
     });
   $("#id").html(function(i, val) { return val*1+1 });
  }
 });

This is a better option than adding a state attribute to the actual DOM element.

Upvotes: 0

jfriend00
jfriend00

Reputation: 708136

You can set a data attribute on both objects and only increment the counter if that is not set:

$('.class, #id').one('click', function(e) {
   if (!$(this).data("valueSet")) {
       $('.class, #id').css({
           'background-color' : 'rgb(232,69,73)',
           'color' : '#fff'
       }).data("valueSet", true);
       $("#id").html(function(i, val) { return val*1+1 });
    }
 });

Or, if you know there are no other jQuery click handlers that you want to retain, you can unbind all jQuery click handlers from both objects:

$('.class, #id').one('click', function(e) {
    $('.class, #id').off("click").css({
        'background-color' : 'rgb(232,69,73)',
        'color' : '#fff'
    })
    $("#id").html(function(i, val) { return val*1+1 });
 });

Or, you can unbind just this specific event handler by putting the event handler in a named function:

function oneClick(e) {
    $('.class, #id').off("click", oneClick).css({
        'background-color' : 'rgb(232,69,73)',
        'color' : '#fff'
    })
    $("#id").html(function(i, val) { return val*1+1 });
}

$('.class, #id').one('click', oneClick);

A little more generic scheme would create a custom function that will only ever perform its action once:

function oneAction(fn) {
     var calledYet = false;
     return function() {
          if (!calledYet) {
              calledYet = true;
              return fn.apply(this, arguments);
          }
     }
 }

Then, you can use this:

$('.class, #id').one('click', oneAction(function(e) {
    // this will only ever be executed once
    $('.class, #id').css({
        'background-color' : 'rgb(232,69,73)',
        'color' : '#fff'
    })
    $("#id").html(function(i, val) { return val*1+1 });
}));

Upvotes: 2

Related Questions