skip to Main Content

Trying to learn some php and mysql, so I’m working on a todo list where I want the todo tasks get a line-through when a checkbox that each task has is checked and removed again if unchecked.

like i have here:

enter image description here

I have made so i can make the line-through from a variable in database like this:

<input class="form-check-input form-check-input-todolist flex-shrink-0 my-1 me-2 form-check-input-undefined" type="checkbox" data-event-propagation-prevent="data-event-propagation-prevent" id="checkbox-todo-<?= $todoTask_Data['task_id'] ?>" <?php if($todoTask_Data['task_checked'] == 'true') {echo 'checked';} ; ?> />

Now I need to find out how i add the "true" variable to the task_checked column in mysqli when the checkboxes are clicked.

Not really worked with ajax/js much before, so its been very confusing figuring out how to do this. But I think i got the idea now, but still cant get this to work.

This is the script I got so fare

  $(document).ready(function() {
$('.checkbox-todo').on('change', function() {
  if (this.checked) {
    var checkboxID = $(this).attr('id');


    $.ajax({
      url: "update_TodoTask.php",
      method: "POST",
      data: { checkboxID: checkboxID },
      success: function(response) {

      }
    });
  }
});
});

And inside update_TodoTask.php i got something like this:

if ($_SERVER["REQUEST_METHOD"] === "POST" && isset($_POST['checkboxID'])) {
 $checkboxID = $_POST['checkboxID'];


header('Location: test.php');
}

Here is the html code: https://pastecode.io/s/zw4thpoe

But I don’t even think it is communication with update_TodoTask.php when pressed. should it not be triggering the header location when i press a checkbox?

I’m not sure im telling the ajax script which checkbox in the todo list is pressed correctly?

Can anyone tell me what I’m doing wrong here?

Update:

I am now able to add true to my task_checked collomn in the DB when i click the checkmarks using this:

$(document).ready(function() {
  $('.form-check-input-todolist').on('change', function() {

    var checkboxID = $(this).attr('id');
    let [c, t, id] = checkboxID.split('-');

    $.ajax({
      url: "update_TodoTask.php",
      method: "POST",
      data: {
        checkboxID: checkboxID,
        id: id, // the Integer portion of ID - useful for sql update statement
        state: ( this.checked ? 1 : 0 ) // Boolean - is it checked? - useful for sql update statement
      },
      success: (res) => {
        console.log(res);
      },
      error: (err) => {
        console.log(`${err.statusText} - problem making AJAX request with ID: ${id}`)
      }
    });

  });
});

My update_TodoTask.php looks like this:

    #assumed mySQLi connection
    if( $_SERVER['REQUEST_METHOD']=='POST' && isset(
      $_POST['checkboxID'],
      $_POST['id'],
      $_POST['state'],
  )){
    $checkboxID = $_POST['checkboxID'];
    $id = $_POST['id'];
    $state = $_POST['state'];
    
    $todo_task_checkmark_update = mysqli_query($conn, "UPDATE todo_tasks SET task_checked = 'true' WHERE task_id = $id");

  };

Now when I click one of the checkmarks it updates my DB with "true" value in the task_checked column..

The last thing I need now is to remove the checkmarks from the DB when i uncheckmark a todo item.

I’ve tried doing something like the code below, but can’t get the isset thing to working:

    #assumed mySQLi connection
    if( $_SERVER['REQUEST_METHOD']=='POST' && isset(
      $_POST['checkboxID'],
      $_POST['id'],
      $_POST['state'],
  )){
    $checkboxID = $_POST['checkboxID'];
    $id = $_POST['id'];
    $state = $_POST['state'];

    $query = "SELECT task_checked FROM todo_tasks WHERE task_id = $id";
    $result = $conn->query($query);

    $row = $result->fetch_assoc();
    $todoTask_checkmark_status = $row['task_checked'];


    if (isset($todoTask_checkmark_status)) {
      if ($todoTask_checkmark_status == false) {
          $todo_task_checkmark_update = mysqli_query($conn, "UPDATE todo_tasks SET task_checked = 'true' WHERE task_id = $id");
      } elseif ($todoTask_checkmark_status == true) {
          $todo_task_checkmark_update = mysqli_query($conn, "UPDATE todo_tasks SET task_checked = 'false' WHERE task_id = $id");
      } 
  };

  };

I also tried the isset with $_POST[‘state’] but same problem.. It like it not even running the isset part..

What am I doing wrong?

2

Answers


  1. To ensure that the database is updated to reflect the checked/unchecked/checked nature of the user’s choice you should send an AJAX request for each change event registered on each input element. The AJAX request should also send the checked value so that your can determine whether the table should still say checked or unchecked.

    You can explode the STRING id attribute to determine the actual integer value and also the this.checked boolean value – add those to the POST payload sent via AJAX.

    The PHP code then has the actual (presumably) ID value and a Boolean to be used in the SQL update statement.

    Rather than worry about the Javascript state being a Boolean or String when posted it is easy to replace that with an integer 1 or 0 using simple ternary operator.

    $(document).ready(function() {
      $('.form-check-input-todolist').on('change', function() {
        /* 
          Not sure why you need to send ALL the ID of the checkbox, 
          only the integer is relevant most likely?
          
          so - split the ID into parts and select integer
        */
        var checkboxID = $(this).attr('id');
        let [c, t, id] = checkboxID.split('-');
        /* 
          To reflect checked/unchecked in db the ajax request should be sent 
          whenever the user modifies the input checked status.
        */
        $.ajax({
          url: "update_TodoTask.php",
          method: "POST",
          data: {
            checkboxID: checkboxID,
            id: id, // the Integer portion of ID - useful for sql update statement
            state: ( this.checked ? 1 : 0 ) // Boolean - is it checked? - useful for sql update statement
          },
          success: (res) => {
            console.log(res);
            this.parentNode.classList.toggle('linethrough')
          },
          error: (err) => {
            console.log(`${err.statusText} - problem making AJAX request with ID: ${id}`)
            /* 
            the following should not be here for final version 
            it is here only because the AJAX request WILL fail
            here in the snippet
            */
            this.parentNode.classList.toggle('linethrough')
          }
        });
    
      });
    });
    .linethrough {
      text-decoration: line-through;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    
    
    <label>Task 1
        <input class="form-check-input form-check-input-todolist flex-shrink-0 my-1 me-2 form-check-input-undefined" type="checkbox" data-event-propagation-prevent="data-event-propagation-prevent" id="checkbox-todo-1" />
    </label>
    
    <label>Task 2
        <input class="form-check-input form-check-input-todolist flex-shrink-0 my-1 me-2 form-check-input-undefined" type="checkbox" data-event-propagation-prevent="data-event-propagation-prevent" id="checkbox-todo-2" />
    </label>
    
    <label>Task 3
        <input class="form-check-input form-check-input-todolist flex-shrink-0 my-1 me-2 form-check-input-undefined" type="checkbox" data-event-propagation-prevent="data-event-propagation-prevent" id="checkbox-todo-3" />
    </label>
    
    <label>Task 4
        <input class="form-check-input form-check-input-todolist flex-shrink-0 my-1 me-2 form-check-input-undefined" type="checkbox" data-event-propagation-prevent="data-event-propagation-prevent" id="checkbox-todo-4" />
    </label>

    Your PHP then might be a little like this:

    <?php
        #assumed mySQLi connection
        if( $_SERVER['REQUEST_METHOD']=='POST' && isset(
            $_POST['checkboxID'],
            $_POST['id'],
            $_POST['state'],
        )){
        
            $id=filter_input( INPUT_POST, 'id', FILTER_SANITIZE_NUMBER_INT );
            $state=filter_input( INPUT_POST, 'state', FILTER_SANITIZE_NUMBER_INT );
            
            $sql='update `TABLENAME` set `<COLNAME>`=? where `<ID>`=?';
            $stmt=$db->prepare( $sql );
            $stmt->bind_params('ii',$state,$id);
            $stmt->execute();
            
            exit('ok...or other useful stuff');
        }
    
    ?>
    

    You would not want to use the header call at the end of the script as you have sent an AJAX request rather than a regular HTTP GET request so it will not be honoured. Instead, send meaningful data back to the AJAX callback function – the callback can be used to update the DOM somehow or let the user know they did a good/bad things etc

    Login or Signup to reply.
  2. I have a number of places where I want to indicate that something has been handled. I do it by graying out the option using style.opacity

    This does not even go back to the server. At the same time, I do send an AJAX command to the server to persist the change in the database.

    Is the above your real case? Or might the need for the strikethrough come from some other process? If it is the latter, my answer does not apply.

    The JS approach (with strikethrough or gray-out) has two advantages: A second click can be programmed to undo, and the screen does not jump around. (Previously, I was deleting the text or image — that led to a ‘bad user experience’ of the screen jumping around in seemingly random ways.

    For both do and undo, here is some JS code:

    e = document.getElementById(id);    // Get the text or image
    op = e.style.opacity;               // current opacity
    e.style.opacity = (op == "0.5") ? "1" : "0.5";  // flip
    ajax...;                            // persist the action
    

    (Adapt it for strikethrough if you prefer.)

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search