i am dustin diaz

a JavaScriptr...

boosh.

don't worry about it.

Check one, check all Javascript

Ever since getting "ever so involved" with the DOM in the beginning of this year, I've had the aching habit of going through all my old "copy & paste" scripts and rewriting them myself. So, this entry is only a fraction of the outcome of what has been happening to me thus far.

The Scenario

A form with tabularized items generated from a database. Each item has a checkbox in it's particular row holding an array name for its name attribute and a unique ID for its value. At the top of the form is a stand-alone checkbox which triggers a "check all - check none" event. To top it all off, we need some server side action goin’ on to remove the items that are checked.

The old way

Before moving ahead I thought it would a good idea to show the previous script which I was borrowing from Invision Power Board. This involved two functions that worked together very nicely. Right about now would be a good time to set the style sheet view to "UnDesigned," and if of course you like to jump ahead to the demo, I'll let you do that.

Invisionboard Checkall Functions



//==========================================

// Check All boxes

//==========================================

function CheckAll(fmobj) {

  for (var i=0;i<fmobj.elements.length;i++) {

    var e = fmobj.elements[i];

    if ( (e.name != 'allbox') && (e.type=='checkbox') && (!e.disabled) ) {

      e.checked = fmobj.allbox.checked;

    }

  }

}



//==========================================

// Check all or uncheck all?

//==========================================

function CheckCheckAll(fmobj) {

  var TotalBoxes = 0;

  var TotalOn = 0;

  for (var i=0;i<fmobj.elements.length;i++) {

    var e = fmobj.elements[i];

    if ((e.name != 'allbox') && (e.type=='checkbox')) {

      TotalBoxes++;

      if (e.checked) {

       TotalOn++;

      }

    }

  }

  if (TotalBoxes==TotalOn) {

    fmobj.allbox.checked=true;

  }

  else {

   fmobj.allbox.checked=false;

  }

}
Okay, so as you can see, it really isn't all that bad. A solid group of functions. One for the checkAll, and one for the body of generated items. Here is how I revised it, or better yet, came up with by the best of my ability.

Revised CheckAll Function

function checkAll(ref) {

  var chkAll = document.getElementById('checkAll');

  var checks = document.getElementsByName('del[]');

  var removeButton = document.getElementById('removeChecked');

  var boxLength = checks.length;

  var allChecked = false;

  var totalChecked = 0;

  if ( ref == 1 ) {

    if ( chkAll.checked == true ) {

      for ( i=0; i < boxLength; i++ ) {

        checks[i].checked = true;

      }

    }

    else {

      for ( i=0; i < boxLength; i++ ) {

        checks[i].checked = false;

      }

    }

  }

  else {

    for ( i=0; i < boxLength; i++ ) {

      if ( checks[i].checked == true ) {

        allChecked = true;

        continue;

      }

      else {

        allChecked = false;

        break;

      }

    }

    if ( allChecked == true ) {

      chkAll.checked = true;

    }

    else {

      chkAll.checked = false;

    }

  }

  for ( j=0; j < boxLength; j++ ) {

    if ( checks[j].checked == true ) {

      totalChecked++;

	}

  }

  removeButton.value = "Remove ["+totalChecked+"] Selected";

}
Basically, I combined both functions into one with the only difference being a number that gets passed into the function as an argument. For the main checkAll checkNone button (at the top or bottom of your form), you pass in the number "1", and for everything else, you could pass in whatever you want, as long as it's not 1. Preferably something like "2" would suffice. You'll also notice in my nifty function that I added a "Remove totalChecked Selected" feature which displays the amount of checked boxes. I suppose if you wanted you could add in another conditional statement which asks if they're all checked and display "Remove All" instead of displaying a number.

Removing Records with PHP

This part I knew I could definitely improve on. Previously, without the flexibility of putting in unique values for the value="" attribute, this is how I managed to get them out of the database.

PHP Drop Record Database call

<?php

if ( isset($_POST['remove_selected']) ) {

  $q = mysql_query('select id from table');

  while ( $r = mysql_fetch_array($q) ) {

    $message_id = 'msgid_'.$r['id'];

    if ( $$message_id == "yes" ) {

      $del_id = $r['id'];

      $drop_sql = mysql_query(

	  "DELETE FROM table

      WHERE id = '$del_id'

      LIMIT 1");

      if ( ! @$drop_sql ) {

        die ('Unable to Execute the drop query '.mysql_error());

      }

    }

  }

}

?>
Boy that's ugly. Notice the second mysql_query() encapsulated within the while() loop. Mhmm, not good. Anytime you're running loops that send off queries is a potential cause for a database disaster. If you had 50 items to delete, then count on 50 queries being sent to the database server. Fortunately in my case I've never had to delete so many items at once. However even 5 queries is too much...and dare I say, even 2 is too much.

The case is IN

With the javascript now being able to intake the database ID's directly into the value attribute of the checkbox, we can now rewrite our drop script as follows:

Using the SQL 'IN' clause to run faster queries

<?php

if ( isset($_POST['remove_selected']) ) {

  $postCount = count($_POST['delAnn']);

  for ( $i=0; $i < $postCount; $i++ ) {

    $deleteIds .= $_POST['del'][$i].',';

  }

  $deleteIds = rtrim($deleteIds,',');

  mysql_query('delete from table where id in ('.$deleteIds.')');

}

?>
Yep. It really is that easy. Not that you've already been doing this already. Sometimes I just tend to be a little behind the times. I used to think the longer and more complicated the script was, the better programmer I would be reveered for. *Cough B.S.* With the above function, all you're doing is gathering the ids, storing them in a comma delimitted string (not array), remove the last comma with rtrim(), then using mysql's keyword "IN" to delete specific id's.

With all this said and done, view the JS CheckAll demo to play around with yourself.

this is who i am

Hi, my name is Dustin Diaz and I'm an Engineer @ObviousCorp. Previously @Twitter, @Google, and @Yahoo, author of Strobist® Info co-author of JavaScript Design Patterns, co-creator of the Ender JavaScript Framework, a Photographer, and an amateur Mixologist. This is my website. Welcome!

On this site I write about JavaScript. You can also follow along with my open-source work on Github.

This site is optimized and works best in Microsoft Internet Explorer 6.