Toggle non-consecutive checkboxes with jQuery UI

You’re all probably familiar with the UI convention of allowing users to select ALL or NONE for a list of checkboxes (like in Gmail). Recently I was working on a project that had a large table full of checkboxes (imagine a 10x10 grid) where the user would need to toggle some but not all of the checkboxes in a given row. And to make matters more complex, they would need to toggle groups of non-consecutive checkboxes (say 15, skip 10, 5, etc.). I threw on the thinking cap but couldn’t think of any similar interactions I’d seen and couldn’t think of a particularly good way to achieve this.

Enter jQuery UI. I happened to stumble across the jQuery UI Selectable documentation and realized it would provide a good UI experience to toggle some but not all of the checkboxes. The code to implement this is surprisingly simple:

Note: You don’t actually need the div container - that was just for JSFiddle.
<div id="checkboxes">

<table id="checkboxTable">
     <tr>
         <td><input type="checkbox" /></td>    
          <td><input type="checkbox" /></td>
          <td><input type="checkbox" /></td>
          <td><input type="checkbox" /></td>
     </tr>
     <tr>
         <td><input type="checkbox" /></td>    
          <td><input type="checkbox" /></td>
          <td><input type="checkbox" /></td>
          <td><input type="checkbox" /></td>
     </tr>
     <tr>
         <td><input type="checkbox" /></td>    
          <td><input type="checkbox" /></td>
          <td><input type="checkbox" /></td>
          <td><input type="checkbox" /></td>
     </tr>
     <tr>
         <td><input type="checkbox" /></td>    
          <td><input type="checkbox" /></td>
          <td><input type="checkbox" /></td>
          <td><input type="checkbox" /></td>
     </tr>
     <tr>
         <td><input type="checkbox" /></td>    
          <td><input type="checkbox" /></td>
          <td><input type="checkbox" /></td>
          <td><input type="checkbox" /></td>
     </tr>
</table> 
</div> 

And then the Javascript (jQuery + jQuery UI):

$("#checkboxes").selectable( {filter: "input:checkbox",
            stop: function(event, ui) {
                
                $(".ui-selected").each( function(){

                    $(this).each( function(){
                        var val = $(this).attr("checked") ? null : "checked";
                        $(this).attr("checked", val);
                    });
                    
                });
}});

You can check out a live demo at http://jsfiddle.net/whMyQ/3/

As always, questions and comments are welcome!

jQuery: binding DOM events to objects

A few days ago I was working on a project for a client that basically involved allowing a non-technical end user to build arbitrarily complex boolean queries using a UI. The user could basically click, configure, and drag/drop queries to build expressions like (A AND B OR C) AND (Z OR X). They would also need the ability to edit the pieces in-line, toggle ANDs to ORs, and so on.

Anyway, not to difficult to represent with a data structure but the complexity was going to be in tying the UI to the data structure with callbacks and events. Usually, I would of used a single $(“a”).click() handler to handle all the edit, delete, and configuration clicks in the UI but that quickly devolves into a disastrous mess of if statements and hasClass() checks.

Hoping to avoid this, I started thinking about cleaner ways to implement this and realized if I actually bound events to the individual objects they were going to effect the resulting code would be much cleaner. The UI elements were going to be dynamically generated each time the data structure was updated anyway so binding $.click() events on the <a> tags to their corresponding objects wouldn’t be to much extra work.

All in all, things worked out pretty well. The final code is much easier to follow and there isn’t a gigantic if() block which is impossible to trace.

I can’t share the actual implementation I used but I threw together an example which outlines the technique. Check out the JSFiddle at http://jsfiddle.net/fN46q/4/

Looking at the code, the Board object is an Array that in turn contains Piece objects to form a 3x3 grid.

The Piece objects individually supply a render function to display themselves and then contain a click() function which handles their $.click() events.

The key line which makes this work is:

   $(td).find("a").bind("click", {piece: this[i][j]}, this[i][j].click);

What the second parameter does is add the object into the Event object that is passed to the event handler. More info is available on the $.bind() documentation but looking at the click() function in the Piece object you can see where it comes in to play:

 click: function( e ){
    e.data.piece.val = !e.data.piece.val;
    e.data.piece.board.render();
    return false;
 }

So effectively, the data structure is now linked to the DOM.

As always, thoughts, comments and are feedback welcome!

jQuery UI confirm

I was looking around earlier for a jQuery plugin to allow me to use jQuery UI’s dialog() widget to popup a confirm dialog. Didn’t have any luck finding one so I whipped something up. It’s not pretty but it works. You could even go as far as to overload window.confirm() but thats probably a bad idea.

jQuery.confirm = function(options){
	
	var opts = jQuery.extend( { message: "", ok: function(){}, cancel: function(){ } }, options );
	
	jQuery("<div class='span-10'><div class='ui-confirm-message'>" 
				+ opts.message + "<img class='loader' style='padding-left: 10px' src='/images/loader.gif' />" 
				+ "</div></div>").dialog({
					autoOpen: true,
					modal: true,
					autoOpen: false,
					resizable: false,
					draggable: false,
					title: "",
					width: "400px",
					buttons: {
					    "Cancel": function(){ 
							opts.cancel.call( this ); 
						},
						"Ok": function(){ 
					    	opts.ok.call( this );
					    }
					}
	}).dialog("open");
	
	
};

// use it 

		jQuery.confirm( {
			"message": "Are you sure?",
			"ok": function( ){
				
				$(this).find(".loader:first").show();
				
				// do stuff
                               $(this).dialog("close");
			},
			"cancel": function( ){ 
				$(this).dialog("close");
			}
		});

iPhone style checkboxes for Symfony

No one worry, I did in fact survive my birthday and subsequent party!

Anyway, I was poking around for some cool UI elements for checkboxes and stumbled across this neat jQuery plugin - http://github.com/tdreyno/iphone-style-checkboxes Basically, what it does is converts checkboxes into iPhone style toggles.

Check out a demo at http://tdreyno.github.com/iphone-style-checkboxes/

This is for a symfony project (shocker!), so I figured I’d roll it into a widget and share.

You’ll need to download and include the JS+CSS+images for the plugin yourself and then copy the following code into your project:

<?php
class sfWidgetFormInputiPhoneCheckbox extends sfWidgetFormInputCheckbox {

	public function __construct($options = array(), $attributes = array())
	{
		
		$this->addOption('checked_label');
        $this->addOption('un_checked_label');
        
		parent::__construct($options, $attributes);
	}

	public function render($name, $value = null, $attributes = array(), $errors = array())
	{
		$str = parent::render( $name, $value, $attributes, $errors );
        
		$checkedLabel = $this->getOption("checked_label");
        $uncheckedLabel = $this->getOption("un_checked_label");
        $id = $this->generateId($name);
        
        
		$str .= <<<EOF
		<script type='text/javascript'>
		  
		  $(document).ready( function(){
		  
                $('#$id').iphoneStyle({
                    checkedLabel: '$checkedLabel',
                    uncheckedLabel: '$uncheckedLabel'
                });
                
		  });
		</script>
EOF;

		return $str;
	}

}

Using it is straightforward:

    $this->setWidgets(array(
      'show-upcoming-events-nav' => new sfWidgetFormInputiPhoneCheckbox( array("checked_label" => "on", "un_checked_label" => "off") ),
    ));

jQuery.trigger weirdness

Earlier today, I was trying to use jQuery to trigger the submission of a form after a radio button was clicked. The form tag looked something like:

    <form action="" id="someForm" method="GET" onsubmit="saysomething(); return false">
   ...form..
   </form>

    <script type="text/javascript">
    
    function saysomething(){
      alert("Hello world from saysomething()");
    }

   </script>

So for a regular submit button:

  <input type="submit" value="Submit Form" />

Everything works fine, you’ll see the alert() and the form won’t submit because of the return false.

I ran into issues when I tried to trigger() the submit event with jQuery. I was trying to trigger the submit() event on the form via jQuery. The problem I ran into, was that the saysomething() function was getting called, but the “return false” seemed to have no effect.

The final form looked something like:

    <form action="" id="someForm" 
          method="GET" onsubmit="saysomething(); return false">
      <input type="text" name="someshit" />
      <input type="submit" value="Submit Form" />
      <input type="button" value="jQuery.submit()" id="clickIt" />
    </form>

    <script type="text/javascript">
    
    function saysomething(){
      alert("Hello world from saysomething()");
    }
    
    $(document).ready( function(){
      $("#clickIt").click( function(){ $("#someForm").submit(); });
    });
    
    </script>

For some reason, if you submit the form via a jQuery trigger the form submits even though saysomething() gets called. I’m not sure if this is the expected behavior but it was certainly something of a shock. Anyway, a live version of the form is running here.