Search code examples
javascriptphphtmlajax

Why is my AJAX form refreshing the page when I submit?


I am creating a simple Follow/Unfollow system, everything works fine in the sense that it inserts the row and deletes the row when I follow/unfollow, but for some reason it refreshes the page every time, even though I'm using e.preventDefault();, why is this? Thanks

<div class="followBtns showFollowDiv">
   <form method="POST" action="">
     <input type="hidden" value="<?php echo $username; ?>" name="username">
     <input type="hidden" value="<?php echo $grabUser['username']; ?>" name="following">
     <input type="hidden" value="<?php echo date('Y/m/d H:i:s'); ?>" name="date">

     <div id="followButtonContainer">
       <?php if ($is_following): ?>
         <button class="followBtn" type="button" value="unfollow" name="action">Unfollow</button>
       <?php else: ?>
          <button class="followBtn" type="button" value="follow" name="action">Follow</button>
       <?php endif; ?>
       </div>
      </form>
     </div>

This is my script at the bottom of my webpage:

  <script type="text/javascript">
  //~~~~~~~~~~~~~~~~~~~~ SCRIPT FOR FOLLOWING A USER ~~~~~~~~~~~~~~~~~~~~//
 $(document).ready(function() {
  console.log("Follow function is working..");
  $(".followBtn").on("click", function(e) {
    // Prevent the default behavior of the button
    e.preventDefault();

    // Check if the button triggers the login modal
    if ($(this).hasClass('followBtn-signin')) {
        $('#loginModal').modal('show'); // Show login modal
        return;
    }

    var followButton = $(this);
    var formDataFollow = {
      'FollowUser': true,
      'username': $('input[name="username"]').val(),
      'following': $('input[name="following"]').val(),
      'date': $('input[name="date"]').val(),
      'action': $(this).val()
  };
    console.log(formDataFollow);
    $.ajax({
        type: "POST",
        url: "/Blog/resources/PHP/FollowUserPHP.php",
        data: formDataFollow,
        dataType: 'json',
        success: function(response) {
            $('#followButtonContainer').html(response.button);
            // Toggle the button text based on the response
            if (response.status === "followed") {
                // Increment the follower count on the frontend
                var followerCountElement = $('.follower-count');
                followerCountElement.text(parseInt(followerCountElement.text()) + 1);
            } else if (response.status === "unfollowed") {
                // Decrement the follower count on the frontend
                var followerCountElement = $('.follower-count');
                followerCountElement.text(parseInt(followerCountElement.text()) - 1);
            }
        },
        error: function(xhr, status, error) {
            console.log(error);
        }
    });
  });
});
</script>

and this is my FollowUserPHP.php:

 <?php
 session_start();
 require_once '/var/www/vhosts/ggweb3.xyz/httpdocs/PHP/connect.php';

 if (isset($_POST['username']) && isset($_POST['following']) && isset($_POST['date']) && isset($_POST['action'])) {
  $username = filter_var($_POST['username'], FILTER_SANITIZE_STRING);
  $following = filter_var($_POST['following'], FILTER_SANITIZE_STRING);
  $date = filter_var($_POST['date'], FILTER_SANITIZE_STRING);
  $action = $_POST['action'];

// Check if the user is already following the viewed user
$stmt_check = $dbh->prepare("SELECT COUNT(*) AS following_count FROM followers WHERE username = :username AND following = :following");
$stmt_check->bindParam(':username', $username, PDO::PARAM_STR);
$stmt_check->bindParam(':following', $following, PDO::PARAM_STR);
$stmt_check->execute();
$fetchFollowing = $stmt_check->fetch();
$is_following = ($fetchFollowing['following_count'] > 0);

if ($action == 'follow' && !$is_following) {
    $stmt = $dbh->prepare("INSERT INTO `followers` (`username`, `following`, `date`) VALUES (:username, :following, :date)");
    $stmt->bindParam(':username', $username, PDO::PARAM_STR);
    $stmt->bindParam(':following', $following, PDO::PARAM_STR);
    $stmt->bindParam(':date', $date, PDO::PARAM_STR);
    $stmt->execute();
    $response = array('status' => 'followed', 'button' => '<button class="followBtn" type="button" value="unfollow" name="action">Unfollow</button>');
} elseif ($action == 'unfollow' && $is_following) {
    $stmt = $dbh->prepare("DELETE FROM `followers` WHERE `username` = :username AND `following` = :following");
    $stmt->bindParam(':username', $username, PDO::PARAM_STR);
    $stmt->bindParam(':following', $following, PDO::PARAM_STR);
    $stmt->execute();
    $response = array('status' => 'unfollowed', 'button' => '<button class="followBtn" type="button" value="follow" name="action">Follow</button>');
   } else {
    // Invalid action value or user is already following/unfollowing
    $response = array('error' => 'Invalid action or user is already following/unfollowing');
}
} else {
// Missing parameters
$response = array('error' => 'Missing parameters');
}

// Output the response as JSON
header('Content-Type: application/json');
echo json_encode($response);
exit;
?>

Solution

  • When you do $('#followButtonContainer').html(response.button); in the AJAX callback you replace the follow button with a new button. This new button does not have the event listener (that is create when the page loads), so you either you need to add an event listener to that new button or have the event listener on a parent element that is not replaced.

    Here, I add the event listener again in the callback (the code only works for inserting the unfollow button because the AJAX request i static with a data URI):

    $(document).ready(function() {
      console.log("Follow function is working..");
      $(".followBtn").on("click", followClicked);
    });
    
    function followClicked(e) {
      // Check if the button triggers the login modal
      if ($(this).hasClass('followBtn-signin')) {
        $('#loginModal').modal('show'); // Show login modal
        return;
      }
    
      var followButton = $(this);
      var formDataFollow = {
        'FollowUser': true,
        'username': $('input[name="username"]').val(),
        'following': $('input[name="following"]').val(),
        'date': $('input[name="date"]').val(),
        'action': $(this).val()
      };
      console.log(formDataFollow);
      $.ajax({
        type: "POST",
        url: `data:application/json,{"button":"<button class='followBtn' type='button' value='unfollow' name='action'>Unfollow</button>","status":"followed"}`,
        data: formDataFollow,
        dataType: 'json',
        success: function(response) {
          $('#followButtonContainer').html(response.button);
          $(".followBtn").on("click", followClicked);
          // Toggle the button text based on the response
          if (response.status === "followed") {
            // Increment the follower count on the frontend
            var followerCountElement = $('.follower-count');
            followerCountElement.text(parseInt(followerCountElement.text()) + 1);
          } else if (response.status === "unfollowed") {
            // Decrement the follower count on the frontend
            var followerCountElement = $('.follower-count');
            followerCountElement.text(parseInt(followerCountElement.text()) - 1);
          }
        },
        error: function(xhr, status, error) {
          console.log(error);
        }
      });
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
    <div class="followBtns showFollowDiv">
      <form method="POST" action="">
        <input type="hidden" value="user01" name="username">
        <input type="hidden" value="user02" name="following">
        <input type="hidden" value="2024/03/25 15:00:00" name="date">
    
        <div id="followButtonContainer">
          <button class="followBtn" type="button" value="follow" name="action">Follow</button>
        </div>
      </form>
    </div>