Mateus Melo Mateus Melo - 5 months ago 16
jQuery Question

jQuery click event weird behavior

I have a list of buttons to make changes to a forum (each button containing an unique data-mod attribute value). I wrote a jquery script to handle the last clicked button and send its value to a php database handler via ajax, which also sends a custom alert confirmation whether the moderator really wants to do the action or not (if not, alert closes and nothing happens, else, callback function is called).

However, I'm experiencing a weird behavior with this script, which regards the fact that even though I cancel the confirmation, the next confirmed alert will fire the callback function depending on how many times I've clicked the buttons. What I want is the callback function being fired one time with the last confirmed action.

$(function() {
var btn;
// Custom callback function
function callback(clicked) {
$("#result").append("<br/>").append(clicked);
}
// Custom alert function
var alert = {
Check: function(fnc, clicked) {
$("#alert").show();
$("[data-alert=1]").click(function() {
fnc(clicked);
alert.Close();
});
$("[data-alert=0]").click(function() {
alert.Close();
});
},
Close: function() {
$("#alert").hide();
return false;
}
};
// Custom button function
$("[data-mod]").click(function() {
btn = $(this);
return alert.Check(callback, btn.data("mod"));
})
});


If description of the error wasn't clear enough, I've wrote a simplified fiddle so you can make changes at the code: here.

Also, if the error seems a little bit confusing, here's a picture of the reproduction:
I want only the last clicked button with the "Yes" confirmation button pressed

Thanks in advance!

Answer

The reason is that the Yes and No button displayed on the alert for your different buttons are the same every time.

So everytime the window pops up you bind a new click function to your yes button, and when you finally click it all the bound functions will trigger.

  //This code is called everytime a button is clicked, so your Yes and No
  //Button will execute as many callbacks when clicked.
  $("[data-alert=1]").click(function() {
    fnc(clicked);
    alert.Close();
  });
  $("[data-alert=0]").click(function() {
    alert.Close();
  });

As for the solution, just bind the click event to Yes or No once (not every time a button is clicked), store the last button clicked in a global variable (or whatever property or whatever element) and retrieve it in your callback function.

$(function() {
var btn;
// Custom callback function
function callback(clicked) {
    $("#result").append("<br/>").append(clicked);
}
// Custom alert function
var alert = {
   Check: function(fnc, clicked) {
      $("#alert").show();
      $("#alert").attr("last-clicked", clicked);
    },
    Close: function() {
      $("#alert").hide();
      return false;
   }
};

//Only called once
$("[data-alert=1]").click(function() {
  callback($("#alert").attr("last-clicked"));
  alert.Close();
});
$("[data-alert=0]").click(function() {
  alert.Close();
});

// Custom button function
$("[data-mod]").click(function() {
   btn = $(this);
   return alert.Check(callback, btn.data("mod"));
})
});

An alternative is to use .off to remove all previous click bindings to your button, like such:

  $("[data-alert=1]").off("click").click(function() {
    fnc(clicked);
    alert.Close();
  });

But the downside is that it will remove all callbacks to the click events, even those that another part of the code could have put there. That's why maybe you're better off doing something like:

  $(document).on("click", "[data-alert=1]", function(...) {...});

Call this once and this will work even for dynamically created alert windows after this call.

Comments