Home > database >  Prevent jQuery code from executing multiple times
Prevent jQuery code from executing multiple times

Time:07-07

When I click on reply button 1 and reply button 2 alternatively, then the second time I click on reply button 2, the code fires multiple times. Kindly assist me to stop the code from firing multiple times. I have gone through similar questions on SO but I have not yet had solution.

Edit: I want the post_reply function to be called only after the first ajax call has been successful and that the #reply-btn-2 button has been clicked

Edit 2: My original code works like this:

(1) When reply button 1 is clicked, call first ajax;

(2) When the first ajax is successful, create new HTML button called reply button 2

(3) When the reply button 2 is pressed, react according to the click.

This explains the reason why the post_reply function is called inside the first ajax.

function post_reply(){
    
    $('#reply-btn-2').click(function(e){
        
        var text2 = 'Reply 2<br>';
        
        $.ajax({
            url: 'ajax.php',
            type: 'POST',
            data: {'submit':1, 'post':2}
            
        }).done(function(response){
            $('.place-replies-here').append(text2);
            
            
        });
    });
    
}
$('#reply-btn-1').click(function(e){
    
    var text1 = 'Reply 1<br>';
    
    $.ajax({
        url: 'ajax.php',
        type: 'POST',
        data: {'submit':1, 'post':2}
        
    }).done(function(response){
        $('.place-replies-here').append(text1);
        
        
        post_reply();
    
    });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>

<div class = "place-replies-here"></div>

<div id = "reply-btn-1" style = "height:40px; width:100px;background:green;color:#fff; padding:5px; margin:8px;" class = "reply-btn">
    Reply 1
</div> 

<div id = "reply-btn-2"  style = "height:40px; width:100px;background:green;color:#fff;padding:5px; margin:8px;" class = "btn btn-success reply-btn">
    Reply 2
</div> 

CodePudding user response:

Your code had some logic flaws. You added a click event listener to the Reply1 button that when will be fired will add a click event listener to the Reply2. It didn't make sense. Every single time you clicked the button Reply1 it was going to add an extra listener again to the same Reply2 button again and again. So that when the click event will fire for Reply2, it will run all the listeners added to the event.

In this demo I made sure you add the click event listener once only to both the button elements.

Actually the second button doesn't exist at first defined in the html. It gets created when the first button gets pressed the first time. From that moment on if the first button will be clicked again, it won't create infinite buttons again and again.

Plus I used the Promise method always instead of done because otherwise the code wouldn't run at all here.

function createAndAppendSecondButton(){
  //create the element for the second button
  const secondButton =
    $("<button></button>")
      .prop('id','reply-btn-2')
      .addClass('reply-btn btn btn-success')
      .text('Reply 2');           
  
  //attach an click event listener to the element
  secondButton.click(function(e){
    $.ajax({
        url: 'ajax.php',
        type: 'POST',
        data: {'submit':1, 'post':2}            
    })
    //to be replaced with .done(function(response){
    .always(function(response){    
      const text2 = 'Reply 2<br>';        
      $('.place-replies-here').append(text2);                        
    });
  });
  
  //append the element to the dom
  $('#reply-btn-1').after(secondButton);
}

$('#reply-btn-1').click(function(e){    
  $.ajax({
    url: 'ajax.php',
    type: 'POST',
    data: {'submit':1, 'post':2}        
  })
  //to be replaced with .done(function(response){
  .always(function(response){    
    //create the second button only if it didn't exist yet
    if( $('#reply-btn-2').length < 1 )
      createAndAppendSecondButton();
    const text1 = 'Reply 1<br>';      
    $('.place-replies-here').append(text1);                      
  });
});
.place-replies-here{
  border: solid 3px gray;
  padding: 1rem;
}

#reply-btn-1{
  height:40px;
  width:100px;
  background:green;
  color:#fff;
  padding:5px;
  margin:8px;
  cursor: pointer;
}

#reply-btn-2{
  height:40px;
  width:100px;
  background:green;
  color:#fff;
  padding:5px;
  margin:8px;
  cursor: pointer;
}

#reply-btn-2:disabled{
  background: gray !important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>

<div ></div>

<button id="reply-btn-1" >Reply 1</button>

CodePudding user response:

The issue is because your second button event handler is nested within the function called from the first button. Therefore every time you click button one, button 2 gets a duplicated event handler.

To fix this, and DRY the code up, put a common class on both buttons and use that to select them. From there you can use data attributes to store the custom metadata you use in the AJAX request. Using this method means that a single event handler will work for both buttons - and any ones you add in the future - without having to change any lines of JS code.

Also note that you shouldn't put inline CSS in your HTML. You an external stylesheet for that.

Here's working example:

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>

<div ></div>
<div  data-submit="1" data-post="2">Reply 1</div>
<div  data-submit="3" data-post="4">Reply 2</div>
$('.reply-btn').on('click', e => {
  let $btn = $(e.target);
  let text = $btn.text();

  $.ajax({
    url: 'ajax.php',
    type: 'POST',
    data: {
      submit: $btn.data('submit'),
      post: $btn.data('post')
    }
  }).done(function(response) {
    $('.place-replies-here').append(text);
  });
});
.reply-btn {
  height: 40px;
  width: 100px;
  background: green;
  color: #fff;
  padding: 5px;
  margin: 8px;
}

CodePudding user response:

Add a simple check to see if the code is able to run or not. This way you are not binding events. Could be a boolean or a variable that has the current step.

let currentStep = 1;

$('#reply-btn-1').click(function(e) {

  var text1 = 'Reply 1<br>';
  $.ajax({
    url: 'ajax.php',
    type: 'POST',
    data: {
      'submit': 1,
      'post': 2
    }

  }).done(function(response) {
    currentStep = 2;
    $('.place-replies-here').append(text1);
  });
});

$('#reply-btn-2').click(function(e) {

  if (currentStep != 2) return;

  var text2 = 'Reply 2<br>';
  $.ajax({
    url: 'ajax.php',
    type: 'POST',
    data: {
      'submit': 1,
      'post': 2
    }
  }).done(function(response) {
    $('.place-replies-here').append(text2);
  });
});
  • Related