AJAX and PHP toggle button state not working properly

110 Views Asked by At

I am fairly new to AJAX and struggling with this thing which i believe is rather a problem with toggle.php. I have this code which works for the most part. But when page is reloaded manually and toggle is = ON, the states get mixed so button is OFF. PHP does not seem to reset and is ON. I tried changing a few things but cant seem to to find the logic error.

The fetchToggleStatus function was added by chatgpt and brought some help..so might as well delete it.

toggle button.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Button Toggle with AJAX and PHP</title>
</head>
<body>

<button id="toggleButton">Toggle</button>
<div id="resultContainer"></div>

<script>
    document.addEventListener('DOMContentLoaded', function () {
        var toggleButton = document.getElementById('toggleButton');
        var resultContainer = document.getElementById('resultContainer');

        // Fetch the initial toggle state when the page loads
        fetchToggleStatus();

        toggleButton.addEventListener('click', function () {
            var xhr = new XMLHttpRequest();
            xhr.open('POST', 'toggle.php', true);

            xhr.onreadystatechange = function () {
                if (xhr.readyState == 4 && xhr.status == 200) {
                    resultContainer.innerHTML = xhr.responseText;
                    updateButtonAppearance();
                }
            };

            xhr.send();
        });

        function fetchToggleStatus() {
            var xhr = new XMLHttpRequest();
            xhr.open('GET', 'toggle.php', true);

            xhr.onreadystatechange = function () {
                if (xhr.readyState == 4 && xhr.status == 200) {
                    resultContainer.innerHTML = xhr.responseText;
                    updateButtonAppearance();
                }
            };

            xhr.send();
        }

        function updateButtonAppearance() {
            var currentText = toggleButton.innerText;
            var newColor = currentText === 'Toggle OFF' ? 'green' : 'red';
            toggleButton.style.backgroundColor = newColor;
            toggleButton.innerText = currentText === 'Toggle OFF' ? 'Toggle ON' : 'Toggle OFF';
        }
    });
</script>

</body>
</html>

toggle.php

<?php
session_start();

// Check if the toggle is set in the session, initialize if not set
if (!isset($_SESSION['toggle_status'])) {
    $_SESSION['toggle_status'] = false;
}

// Toggle the status only when a POST request is received
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $_SESSION['toggle_status'] = !$_SESSION['toggle_status'];
}

// Return the current status
if ($_SESSION['toggle_status']) {
    echo "Toggle is ON";
} else {
    echo "Toggle is OFF";
}
?>
3

There are 3 best solutions below

2
Raed Addala On

When you reload the page, the session cookie is still sent to the server so when isset($_SESSION['toggle_status']) is called it returns True.

Here is your problem, when you reload the page the value in the session can be set to true. So when doing a get Request you should set the session value to False.

if ($_SERVER['REQUEST_METHOD'] === 'GET') {
    $_SESSION['toggle_status'] = false;
}
0
Don't Panic On

PHP does not seem to reset

Correct, and it should not, you're tracking toggle state in the session, which survives across requests, that's the whole point of the session.

The problem is you're using that saved state to display the text in your resultContainer, but you don't use it to set the state of the button. The button simply toggles every time you click it, no matter what state it starts in. So they will get out of sync.

The fix is to use the saved state from the session to set your button state, just like you do for the container text. You can do that by passing the state received from toggle.php to updateButtonAppearance(), and using it instead of the current button text.

  • Update all uses of updateButtonAppearance() to pass the received text as a parameter:

    updateButtonAppearance(xhr.responseText);
    
  • And update updateButtonAppearance() to use that state:

    function updateButtonAppearance(state) {
        var newColor = state === 'Toggle is OFF' ? 'green' : 'red';
        toggleButton.style.backgroundColor = newColor;
        toggleButton.innerText = state === 'Toggle is OFF' ? 'Toggle ON' : 'Toggle OFF';
    }
    
3
patrick40 On

Ok, i redone the code with the help of chatgpt. Since some tips were helpful but the code was bad from the start, because i was not clear of what i wanted. The tips headed me in the right direction. It looks cleaner(jQuery..) and does now what i want. To not reset state on reload and is in sync with button css.

Here is the full code:

toggle button.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Toggle Button</title>
  <script src="https://code.jquery.com/jquery-3.6.4.min.js"></script>
  <style>
    #toggleBtn {
      padding: 10px;
      cursor: pointer;
    }
    #toggleBtn.on {
      background-color: green;
      color: white;
    }
    #toggleBtn.off {
      background-color: red;
      color: white;
    }
  </style>
</head>
<body>

<h2>Toggle Button</h2>

<button id="toggleBtn">Toggle Status</button>
<p id="status">Status: <span id="statusText">OFF</span></p>

<script>
$(document).ready(function() {
  // Check if there is a stored state in local storage
  var isToggled = localStorage.getItem('isToggled') === 'true';

  // Set the initial state
  updateButton(isToggled);

  // Function to update button text and style
  function updateButton(state) {
    $("#statusText").text(state ? "ON" : "OFF");

    // Remove existing classes
    $("#toggleBtn").removeClass('on off');

    // Add class based on the state
    $("#toggleBtn").addClass(state ? 'on' : 'off');
  }

  // Function to handle button click
  $("#toggleBtn").click(function() {
    // Toggle the state
    isToggled = !isToggled;

    // Update the button text and style
    updateButton(isToggled);

    // Store the state in local storage
    localStorage.setItem('isToggled', isToggled);

    // Send the state to the server using Ajax
    $.ajax({
      type: "POST",
      url: "toggle.php",
      data: { state: isToggled ? 1 : 0 },
      success: function(response) {
        console.log("Server response:", response);
      },
      error: function(error) {
        console.error("Error:", error);
      }
    });
  });
});
</script>

</body>
</html>

toggle.php

<?php
// toggle.php

// Check if the request is a POST request
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // Get the state from the POST data
    $state = isset($_POST['state']) ? $_POST['state'] : null;

    // Perform any server-side processing based on the state (e.g., store in a database)
    
    // For this example, we'll just simulate some server-side processing
    $response = ($state === '1') ? 'Toggle ON' : 'Toggle OFF';

    // Send a response back to the client
    echo $response;
} else {
    // If it's not a POST request, return an error
    http_response_code(405); // Method Not Allowed
    echo "Method Not Allowed";
}
?>