<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Monday By Noon &#187; jQuery</title>
	<atom:link href="http://mondaybynoon.com/tag/jquery/feed/" rel="self" type="application/rss+xml" />
	<link>http://mondaybynoon.com</link>
	<description>A resource for Web designers and developers to read about and discuss their craft.</description>
	<lastBuildDate>Wed, 18 Aug 2010 17:44:22 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>jQuery Enlightenment by Cody Lindley Book Review</title>
		<link>http://mondaybynoon.com/2010/02/01/jquery-enlightenment-book-review/</link>
		<comments>http://mondaybynoon.com/2010/02/01/jquery-enlightenment-book-review/#comments</comments>
		<pubDate>Mon, 01 Feb 2010 15:01:59 +0000</pubDate>
		<dc:creator>Jonathan Christopher</dc:creator>
				<category><![CDATA[Book Reviews]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Opinion]]></category>
		<category><![CDATA[Reviews]]></category>
		<category><![CDATA[Cody Lindley]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[review]]></category>

		<guid isPermaLink="false">http://mondaybynoon.com/?p=750</guid>
		<description><![CDATA[jQuery Enlightenment by Cody Lindley reinvigorated my enthusiasm for technical references. If you're at all interested in learning more about jQuery, or you just want an excellent reference on hand, jQuery Enlightenment is it!]]></description>
			<content:encoded><![CDATA[<div id="hreview-Book-review" class="hreview">
<div class="item description">
<p class="img book-cover"><img src="http://mondaybynoon.com/images/books/jquery-enlightenment.jpg" alt="jQuery Enlightenment Book Cover" /></p>
<p>Occasionally a book will come along and reinvigorate my enthusiasm for the format (over my most common method of education: Web based articles). I&#8217;ve just finished reading <a href="http://jqueryenlightenment.com/"><span class="summary">jQuery Enlightenment</span></a> by <a href="http://codylindley.com/">Cody Lindley</a>, and I must say it&#8217;s done just that. On top of being a &#8216;traditional&#8217; book as far as the structure is concerned, I also read the book in PDF format, a turn off for most people. I must say, though, that there is something about this book that leaves me confident to say that if you (want to) work with jQuery, <strong>you should have it</strong>.</p>
<h2>About the author</h2>
<p>Cody Lindley deserves his own section in this review, not only because he&#8217;s proven himself to be a great author, but because he is a figure head in the community. I&#8217;ve only spoken to Cody here and there, and very briefly, but from what I can tell he&#8217;s a great guy, consistently sharing his knowledge with the community, and doing everything he can to both expand and share the knowledge behind his trade.</p>
<p>If you haven&#8217;t heard of Cody Lindley, I&#8217;m almost certain that you&#8217;ve seen some of his work. Cody authored <a href="http://jquery.com/demo/thickbox/">Thickbox</a>, a modal dialog solution for <a href="http://jquery.com">jQuery</a>. He&#8217;s very well known in the jQuery community, and rightfully so. I aspire to someday achieve the level of knowledge Cody has not only of jQuery, but to JavaScript alone.</p>
<p>To simply be blunt, seeing Cody&#8217;s name on the cover of this book alone convinced me that it&#8217;ll be a good read. I knew for a fact that not only would the information be applicable and up to date, it will be based on best practices as well.</p>
<h3>About jQuery Enlightenment</h3>
<p>I love the aim of this book. If you&#8217;ve had an interest in jQuery you know that there is <strong>a ton</strong> of information out there. I&#8217;d go so far to say that the abundance of information in a way works against what jQuery aims to do in that jQuery is so easy to grasp, many tutorials were written without best practice in mind. The approach in this book is different. As stated in the introduction:</p>
<blockquote><p>jQuery Enlightenment was written to express, in short-order, the concepts essential to intermediate and advanced jQuery development. Its purpose is to instill in you, the reader, practices that jQuery developers take as common knowledge.</p></blockquote>
<p>That&#8217;s only on the eighth page and already I knew I was going to love this book. Instead of jumping right in to code samples, the approach here is to introduce you to the code through the philosophy of jQuery itself. Later on in the introduction, Cody outlines the book at being aimed at three types of readers:</p>
<ol>
<li>Someone looking for the next logical step with jQuery after a brief introduction</li>
<li>JavaScript developers well versed in other libraries, trying to pick up jQuery quickly</li>
<li>A reference book for those already familiar with jQuery</li>
</ol>
<p>I can see that Cody kept his goal in mind throughout the book, as each chapter caters to all three types of readers extremely well. If you fit into any of those categories, <a href="http://jqueryenlightenment.com/">jQuery Enlightenment</a> is for you.</p>
<h3>jQuery Enlightenment Organization</h3>
<p>Another great approach Cody took with this book was aligning it with the <a href="http://docs.jquery.com/">jQuery API</a>, something you&#8217;ll become intimately familiar with as you work with jQuery. As with every API ever written, the documentation can always be improved. That&#8217;s not to say I&#8217;m not appreciative of jQuery&#8217;s API docs, <em>I love them</em>, and I&#8217;ve never had a problem finding a piece of information I needed.</p>
<p>This book though, builds on top of the documentation provided directly by jQuery, and walks you through the points that aren&#8217;t immediately apparent as you read through the official API documentation, especially if you&#8217;re new to JavaScript and/or jQuery.</p>
<p>The other bit I really like about jQuery Enlightenment is the way code samples were included. Cody opted to replicate every snippet on <a href="http://jsbin.com/">JS Bin</a>. While I often opt to rewrite code samples by hand (I find that it helps with information absorption) I think it&#8217;s great that he&#8217;s made that effort, especially when viewing jQuery Enlightenment as more of a reference than learning material.</p>
<h3>The verdict</h3>
<p>I <em>loved</em> reading <a href="http://jqueryenlightenment.com/">jQuery Enlightenment</a> and can&#8217;t recommend it enough if you&#8217;re at all interested in jQuery. Whether you&#8217;re just getting started, or even if you&#8217;ve worked with jQuery for years, I&#8217;m willing to bet you&#8217;ll learn things from this book. I&#8217;ve worked with jQuery for quite some time, and I picked up two solid points that I&#8217;m going to embrace from now forward, and I&#8217;m confident they will improve my usage of jQuery.</p>
<p>I got to this book in my stack of To Read&#8217;s a bit late, and as we all know, jQuery 1.4 (and now jQuery 1.4.1) has been released. What does that mean for jQuery Enlightenment? While I haven&#8217;t spoken directly to Cody, I can only imagine that he&#8217;s in the process of revising the book to include the new greatness 1.4 has to offer. I don&#8217;t think you need to hold off for the update until it&#8217;s released as this book is a completely solid reference to jQuery, and I didn&#8217;t find anything that wasn&#8217;t applicable to the 1.4 release. From what I can gather, the revision of the book is going to have quite a bit more content, and be offered at a discount to current owners. All great news!</p>
<p>Again, I absolutely recommend jQuery Enlightenment for your bookshelf if you&#8217;re interested in jQuery. It&#8217;s one of those books that refreshes my enjoyment of reading technical references and I&#8217;m definitely looking forward to the next release.</p>
<div class="hidden meta">
<p><span class="type">Product</span><br />
reviewed <abbr class="dtreviewed" title="20100201T0800-0500">Feb 1, 2010</abbr><br />
by <span class="reviewer vcard"><span class="fn">Jonathan Christopher</span></span></p>
<p>Rating: <abbr class="rating" title="5">★★★★★</abbr></p>
</div>
</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://mondaybynoon.com/2010/02/01/jquery-enlightenment-book-review/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>A Couple of Quick Tips for JavaScript Optimization</title>
		<link>http://mondaybynoon.com/2009/04/27/a-couple-of-quick-tips-for-javascript-optimization/</link>
		<comments>http://mondaybynoon.com/2009/04/27/a-couple-of-quick-tips-for-javascript-optimization/#comments</comments>
		<pubDate>Mon, 27 Apr 2009 13:51:34 +0000</pubDate>
		<dc:creator>Jonathan Christopher</dc:creator>
				<category><![CDATA[DOM]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Opinion]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Design]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://mondaybynoon.com/?p=460</guid>
		<description><![CDATA[A couple of tips to optimize the speed of your slow JavaScript. Code examples using jQuery.]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m a huge fan of JavaScript. I&#8217;ve spent the past couple years trying to really enhance my knowledge of the subject, and with the volatile ingenuity of the modern Web, I&#8217;m able to pick up new things on a very consistent basis. Keeping myself in check, however, is a recognition that I&#8217;ll never embrace all there is to know about JavaScript. The best I can do is teach myself everything I can, and have consistent discussion with those who know more than me. What better way than publishing?</p>
<p><span id="more-460"></span></p>
<p>I work primarily in <a href="http://jquery.com">jQuery</a> when I write JavaScript. I&#8217;ve become very comfortable with the library, as it meets my needs on a very consistent basis. I&#8217;m not biased, however. With each project, I evaluate whether there&#8217;s a need for a full library such as jQuery. There have been many projects which simply didn&#8217;t need the full functionality of a library as feature-rich, and therefore bigger in file size, as jQuery. Many times I&#8217;ll use a more lightweight library such as <a href="http://www.domassistant.com/">DOMAssistant</a> which lets you build your own library with modules you&#8217;ll be working with. There have been many times where <a href="http://www.robertnyman.com/dlite/">dLite</a> (DOMAssistant Lite) has been more than enough to work with, this site for example.</p>
<p>You should evaluate which library you&#8217;re using on a case-by-case basis as well, as it seems that with jQuery being so popular, many designers simply default to using it with every project, even if they&#8217;re only binding a click event in one area of a website.</p>
<p>As I&#8217;ve been writing more elaborate pieces of JavaScript, I&#8217;ve picked up a bit more knowledge in optimizations. It&#8217;s become my focus lately; trying to write cleaner JavaScript resulting in faster processing and therefore a better experience for the user. I&#8217;d like to quickly discuss a couple things I&#8217;ve started doing to ease the load of JavaScript on the browser and therefore the user.</p>
<h2>Creating reference variables</h2>
<p>Traversing the <acronym title="Document Object Model">DOM</acronym> is sometimes expensive, depending on your selector. Keeping node selection to a minimum will help speed up your scripts quite a bit. If you&#8217;re working with a specific node repeatedly, it will probably be in your best judgement to define a variable with that node, instead of traversing for it repeatedly.</p>
<p>For example, if you need to manipulate multiple children of a parent element, it is probably in your best interest to define the parent element as a variable, and work with the children from there.</p>
<p>While not a gigantic enhancement, we can project the benefits on a larger scale, especially when working with a <code>classed</code> element as opposed to one which has an <code>id</code>. This comes in especially handy if you&#8217;re nesting animations, and you need to work with the initial element throughout the process. You can simply reference the variable you&#8217;ve defined instead of possibly having to hunt for a <code>parent()</code> or two.</p>
<p>While libraries such as <a href="http://sizzlejs.com/">Sizzle</a> are dramatically enhancing node selection, it&#8217;s always good practice to write inexpensive code, and sometimes selector abstraction is the way to go.</p>
<h2>Avoiding iterative DOM manipulation</h2>
<p>Perhaps the biggest change to embrace was to avoid manipulating the DOM iteratively. That is to say, making a change to the DOM each time you run through a loop. This practice is definitely not limited to jQuery, but I&#8217;ll be using jQuery syntax in code samples throughout this article.</p>
<p>Keeping this in mind came in very handy as I was working with <a href="http://mondaybynoon.com/2009/02/23/creating-custom-form-elements-using-jquery-selects/">creating custom <code>selects</code> via jQuery</a>. Essentially what I needed to do was loop through an existing <code>select</code> and duplicate each <code>option</code> <code>value</code> as a list item in a newly created list. At first you may write your snippet like so:</p>
<pre class="sh_javascript"><code>// parse all options within the select and set indices
var i = 0;
targetselect.find('option').each(function()
{
  // add the option
  target.find('.options ul').append('&lt;li&gt;&lt;a href=&quot;#&quot;&gt;&lt;span class=&quot;value&quot;&gt;' + $(this).text() + '&lt;/span&gt;&lt;span class=&quot;hidden index&quot;&gt;' + i + '&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;');

  // check to see if this is what the default should be
  if($(this).attr('selected') == true)
  {
    targetselect.parent().find('a.dropdown_toggle').append('&lt;span&gt;&lt;/span&gt;').find('span').text($(this).text());
  }
  i++;
});</code></pre>
<p>You&#8217;ll notice that with each iteration of the loop, we&#8217;re appending a list element to our unordered list. If you&#8217;re running this function on a document with quite a few <code>selects</code> (especially with many <code>options</code>), you&#8217;ll notice quite a bit of lag.</p>
<p>This code can be better optimized by abstracting the injection until after processing the <code>select</code> in its entirety by concatenating the list items to a string, and then appending that string a single time:</p>
<pre class="sh_javascript"><code>// parse all options within the select and set indices
var i = 0;
var options = '';
targetselect.find('option').each(function()
{
  // add the option
  options += '&lt;li&gt;&lt;a href=&quot;#&quot;&gt;&lt;span class=&quot;value&quot;&gt;' + $(this).text() + '&lt;/span&gt;&lt;span class=&quot;hidden index&quot;&gt;' + i + '&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;';

  // check to see if this is what the default should be
  if($(this).attr('selected') == true)
  {
    targetselect.parent().find('a.dropdown_toggle').append('&lt;span&gt;&lt;/span&gt;').find('span').text($(this).text());
  }
  i++;
});
target.find('.options ul').append(options);</code></pre>
<p>Instead of appending the list item with each iteration, which becomes very expensive very quickly, we simply build a string and work with it once the heavy lifting has been done.</p>
<h3>Do you have any tips?</h3>
<p>I know these tips are nothing extraordinary, but I hope they may help you enhance the performance of your future scripts. I realize that my code examples use jQuery syntax, the tips themselves can be applied to any implementation of JavaScript.</p>
<p>Do you have any techniques you&#8217;re using consistently in the interest of both code organization as well as optimization?</p>
]]></content:encoded>
			<wfw:commentRss>http://mondaybynoon.com/2009/04/27/a-couple-of-quick-tips-for-javascript-optimization/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Creating Custom Form Elements Using jQuery: Selects</title>
		<link>http://mondaybynoon.com/2009/02/23/creating-custom-form-elements-using-jquery-selects/</link>
		<comments>http://mondaybynoon.com/2009/02/23/creating-custom-form-elements-using-jquery-selects/#comments</comments>
		<pubDate>Mon, 23 Feb 2009 06:39:34 +0000</pubDate>
		<dc:creator>Jonathan Christopher</dc:creator>
				<category><![CDATA[Design]]></category>
		<category><![CDATA[Examples]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[custom]]></category>
		<category><![CDATA[elements]]></category>
		<category><![CDATA[enhancement]]></category>
		<category><![CDATA[form]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[progressive]]></category>
		<category><![CDATA[select]]></category>
		<category><![CDATA[widgets]]></category>

		<guid isPermaLink="false">http://mondaybynoon.com/?p=385</guid>
		<description><![CDATA[How to progressively enhance your form select dropdowns using JavaScript (jQuery)]]></description>
			<content:encoded><![CDATA[<p>In Web design, there are a number of guidelines to follow. Guidelines based on past experience, user data, and other various sources of information used to support good design practice. There are entire schools of thought surrounding certain guidelines, many of which undergo rounds of scrutiny and revision on a consistent basis. One particular sect of Web design that I have become increasingly interested in is that of conventions used in <code>form</code> design.</p>
<p>We all know what it&#8217;s like to use a terribly designed form; <em>irritating</em>. It&#8217;s difficult enough to get an average reader to take the time to fill out a <code>form</code>, and not following a basic ruleset can turn away any reader in the blink of an eye.</p>
<p>One particular aspect of <code>form</code> design that has been partially taboo is the revision and customization of input widgets. The trouble with form widgets is the uniqueness not only between browsers, but operating systems especially. Altering input elements your reader has become intimately accustomed to using is not a practice to be taken lightly.</p>
<p>A recent client project brought about rare circumstances under which my team felt comfortable experimenting with some custom <code>form</code> widgets. After the first rounds of design had been put together, the custom <code>form</code> elements did an extraordinary job bringing the entire concept together. We decided to run with it. By far the most unique element was the <code>select</code>.</p>
<p>I knew from the start that the <code>selects</code> would be progressively enhanced, defaulting to stock browser <code>form</code> elements out of the box. We&#8217;ve all seen custom <code>form</code> elements before, and I knew there were some pre-fabricated solutions out there. There are even plugins for <a href="http://www.jquery.com">jQuery</a> already. I had a look, but ultimately decided I would roll my own. I&#8217;d like to walk through my thought process as I prototyped a visual example for the client.</p>
<h2>Laying the foundation for a custom select</h2>
<p>What we&#8217;ll first begin with is the markup I use when including a <code>select</code> in my forms:</p>
<pre class="sh_html"><code>&lt;form id=&quot;frm_prototype&quot; action=&quot;index.php&quot; method=&quot;post&quot;&gt;
  &lt;fieldset&gt;
    &lt;legend&gt;Custom Select Test&lt;/legend&gt;
    &lt;div class=&quot;select&quot;&gt;
      &lt;label for=&quot;misc&quot;&gt;Misc&lt;/label&gt;
      &lt;select name=&quot;misc&quot;&gt;
        &lt;option value=&quot;1&quot;&gt;One&lt;/option&gt;
        &lt;option value=&quot;2&quot;&gt;Two&lt;/option&gt;
        &lt;option value=&quot;3&quot;&gt;Three&lt;/option&gt;
      &lt;/select&gt;
    &lt;/div&gt;
    &lt;div class=&quot;buttons&quot;&gt;
      &lt;button type=&quot;submit&quot; id=&quot;submit&quot; name=&quot;submit&quot;&gt;Submit&lt;/button&gt;
    &lt;/div&gt;
  &lt;/fieldset&gt;
&lt;/form&gt;</code></pre>
<p>Your markup may very well differ, as my past experience shows that various designers are slightly particular about <code>form</code> markup. I also began with just a bit of simple CSS on top of that:</p>
<pre class="sh_css"><code>form { margin-bottom:25px; }
form fieldset { border:0; }
form div { clear:left; padding:10px 0; }
form legend { font-size:16px; font-weight:bold; }
form label { display:block; width:75px; float:left; }
form select { display:block; width:225px; float:left; }
form button { padding:5px; }</code></pre>
<p class="single_link"><a href="http://mondaybynoon.com/examples/custom-select/step-1/">View Step 1</a> (note: form submission <em>is not functional</em>)</p>
<h3>Making a plan for the customization</h3>
<p>I wanted to keep the progressive enhancement as semantic as possible, so I took a step back and thought about what a <code>select</code> represented, save the functionality. To me, a <code>select</code> includes a representative item from a set of available alternatives. In essence, the chosen value defines the <code>select</code>. The defining relationship stuck, and I elected to base my markup variations around a definition list.</p>
<p>Next, I took a few minutes to think about how I planned on executing the progressive enhancement. I came up with the following list of steps I&#8217;d take to recreate the interaction of the original <code>select</code> while retaining the integrity of the <code>form</code> itself; we still needed the data to submit properly.</p>
<ol>
<li>After the <acronym title="Document Object Model">DOM</acronym> was ready, loop through all <code>selects</code>. For each <code>select</code>:</li>
<li>Hide the element itself</li>
<li>Append my new markup</li>
<li>Loop through all <code>options</code> for the current <code>select</code> and</li>
<li>Add my own list of options, mirroring those from the original <code>select</code></li>
<li>Bind click events where applicable, making sure to set the proper <code>value</code> on our newly hidden <code>select</code></li>
</ol>
<p>The process seemed straightforward enough, so I began by creating the images I&#8217;d need for the custom <code>select</code>. I began by working with a static version of the enhanced markup (note the addition of a new class, enhanced):</p>
<pre class="sh_html"><code>&lt;form id=&quot;frm_prototype&quot; action=&quot;index.php&quot; method=&quot;post&quot;&gt;
  &lt;fieldset&gt;
    &lt;legend&gt;Custom Select Test&lt;/legend&gt;
    &lt;div class=&quot;enhanced select&quot;&gt;
      &lt;label for=&quot;misc&quot;&gt;Misc&lt;/label&gt;
      &lt;select name=&quot;misc&quot; style=&quot;display:none;&quot;&gt;
          &lt;option value=&quot;1&quot;&gt;One&lt;/option&gt;
          &lt;option value=&quot;2&quot;&gt;Two&lt;/option&gt;
          &lt;option value=&quot;3&quot;&gt;Three&lt;/option&gt;
      &lt;/select&gt;
      &lt;dl class=&quot;dropdown&quot;&gt;
        &lt;dt&gt;&lt;a class=&quot;dropdown_toggle&quot; href=&quot;#&quot;&gt;&lt;span&gt;One&lt;/span&gt;&lt;/a&gt;&lt;/dt&gt;
        &lt;dd&gt;
          &lt;div class=&quot;options&quot;&gt;
            &lt;ul&gt;
              &lt;li&gt;&lt;a href=&quot;#&quot;&gt;One&lt;/a&gt;&lt;/li&gt;
              &lt;li&gt;&lt;a href=&quot;#&quot;&gt;Two&lt;/a&gt;&lt;/li&gt;
              &lt;li&gt;&lt;a href=&quot;#&quot;&gt;Three&lt;/a&gt;&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/div&gt;
        &lt;/dd&gt;
      &lt;/dl&gt;
    &lt;/div&gt;
    &lt;div class=&quot;buttons&quot;&gt;
      &lt;button type=&quot;submit&quot; id=&quot;submit&quot; name=&quot;submit&quot;&gt;Submit&lt;/button&gt;
    &lt;/div&gt;
  &lt;/fieldset&gt;
&lt;/form&gt;</code></pre>
<p>Some revisions to the CSS, of course (reformatted as multi-line for readability in the article):</p>
<pre class="sh_css"><code>/* Used only when enhanced */

.enhanced a {
	font-size: 11px;
	text-decoration: none;
	color: #7e7e7e;
}

.dropdown {
	float: left;
	width: 200px;
	position: relative;
}

.dropdown .options {
	position: absolute;
	left: 5px;
	top: 23px;
	overflow: auto;
	background: #fff;
	width: 169px;
	height: 55px;
	border: 1px solid #c8c8c8;
	border-top: 0;
	padding: 7px 10px;
}

.dropdown .options ul {
	list-style: none;
}

.dropdown .options a {
	display: block;
	font-size: 12px;
	padding: 2px 0;
}

.dropdown .options a:hover {
	text-decoration: underline;
}

a.dropdown_toggle {
	display: block;
	height: 24px;
	background: url(enhanced-select-arrow.jpg) top right no-repeat;
	padding-right: 25px;
}

a.dropdown_toggle span {
	display: block;
	background: url(enhanced-select-bg.jpg) no-repeat;
	padding: 6px 0 0 8px;
	height: 18px;
	cursor: pointer !important;
}</code></pre>
<p class="single_link"><a href="http://mondaybynoon.com/examples/custom-select/step-2/">View Step 2</a> (note: form submission <em>is not functional</em>)</p>
<h3>Writing the JavaScript</h3>
<p>Now that I had some functional markup and style to use as an endpoint, I began with the fun part, writing the JavaScript. There are a number of other areas on the site using jQuery, my library of choice, so I began by including the library (1.3.2 as of this writing).</p>
<p>I had my mental list of steps to begin taking when progressively enhancing the <code>selects</code>, so I started with step 1: wait for the DOM to load, and then loop through all <code>selects</code>:</p>
<pre class="sh_javascript"><code>$(document).ready(function()
{
  $('select').each(function()
  {
    if(!$(this).parent().hasClass('enhanced'))
    {
      targetselect = $(this);
      targetselect.hide();

      // set our target as the parent and mark as such
      var target = targetselect.parent();
      target.addClass('enhanced');
    }
  }
}</code></pre>
<p>Straightforward enough. That snippet of code uses jQuery&#8217;s document ready event to fire the referenced function once the DOM is ready for us. At this stage, we&#8217;re simply adding our enhanced <code>class</code> if it doesn&#8217;t have the class already. While in the loop, we&#8217;ll go ahead and hide the stock <code>select</code>.</p>
<p>Whenever I work with the same element numerous times, I make an effort to declare it as a variable. It helps to not rely on jQuery looking up the element each and every time and instead finding it once and saving that reference as a variable for future use.</p>
<p>Our next goal is to append the markup we used in Step 2. We&#8217;re not able to include all the markup, as we&#8217;ve only traversed to the <code>select</code> itself thus far, so we&#8217;ll only inject the parent elements we know we&#8217;ll need for now.</p>
<pre class="sh_javascript"><code>// prep the target for our new markup
target.append('&lt;dl class=&quot;dropdown&quot;&gt;&lt;dt&gt;&lt;a class=&quot;dropdown_toggle&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;/dt&gt;&lt;dd&gt;&lt;div class=&quot;options&quot;&gt;&lt;ul&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/dd&gt;&lt;/dl&gt;');
target.find('.dropdown').css('zIndex',z);
z--;

// we don't want to see the options yet
target.find('.options').hide();</code></pre>
<p>We&#8217;re also minding the <code>z-index</code> here, as with the creation of each new enhanced <code>select</code>, we&#8217;re going to need to make sure there&#8217;s no improper overlapping. <code>z</code> is a global variable set to 999 at the time of its declaration. With each progressive enhancement, we&#8217;re going to decrement z to ensure proper z-order stacking.</p>
<p>Now we&#8217;ll go ahead and duplicate the <code>options</code> from the original <code>select</code>:</p>
<pre class="sh_javascript"><code>// parse all options within the select and set indices
var i = 0;
var options = '';
targetselect.find('option').each(function()
{
  // add the option
  options += '&lt;li&gt;&lt;a href=&quot;#&quot;&gt;&lt;span class=&quot;value&quot;&gt;' + $(this).text() + '&lt;/span&gt;&lt;span class=&quot;hidden index&quot;&gt;' + i + '&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;';

  // check to see if this is what the default should be
  if($(this).attr('selected') == true)
  {
    targetselect.parent().find('a.dropdown_toggle').append('&lt;span&gt;&lt;/span&gt;').find('span').text($(this).text());
  }
  i++;
});
target.find('.options ul').append(options);</code></pre>
<p>In this snippet, we&#8217;re using our reference variable to find all of the child <code>option</code> elements. For each of those elements, we&#8217;re going to append a list item to the markup we just injected. Through each iteration, we&#8217;re also checking to see which <code>option</code> is currently selected, in order to correctly populate our enhanced <code>select</code>. We also append a second <code>span</code> to each list item to allow the tracking of the <code>option</code> index, we&#8217;ll need this later in order to accurately populate the stock <code>select</code>.</p>
<p>Excellent, now we&#8217;ve got our progressively enhanced select ready to go. The last step will be binding click events in an effort to mimic functionality of the original <code>select</code>.</p>
<h3>Binding click events on our custom select</h3>
<p>The first event we&#8217;ll need to bind is the click event on what we&#8217;ll call the toggle. This is the link we first created, included as a child of the <code>dt</code> element.</p>
<pre class="sh_javascript"><code>// let's hook our links, ya?
$('a.dropdown_toggle').live('click', function()
{
	var theseOptions = $(this).parent().parent().find('.options');
	if(theseOptions.css('display')=='block')
	{
		$('.activedropdown').removeClass('activedropdown');
		theseOptions.hide();
	}
	else
	{
		theseOptions.parent().parent().addClass('activedropdown');
		theseOptions.show();
	}
	return false;
});</code></pre>
<p>The conditional included controls whether or not the associated options list we created earlier is visible or not.</p>
<p>I&#8217;m using a new feature included within jQuery 1.3, the <a href="http://docs.jquery.com/Events/live">live event</a>. It&#8217;s a terrific addition that binds an event for all current <em>and future</em> matched elements. I&#8217;ve elected to use the live event here as there was a possibility for new <code>selects</code> to be created on the fly after the DOM had initially loaded. The live event prevents my having to continually monitor the click events on existing and new toggle links.</p>
<p>Now that the display toggle for our options is in place, we need to also bind to the click events for all of the anchors included in our list of options as well. If any of those anchors are clicked, we need to retrieve the proper value associated with the link, update the toggle link text to reflect the change, and most importantly we need to update the value of the original <code>select</code> that was hidden long ago.</p>
<pre class="sh_javascript"><code>$('.options a').live('click', function(e)
{
	$('.options').hide();

	var enhanced = $(this).parent().parent().parent().parent().parent().parent();
	var realselect = enhanced.find('select');

	// set the proper index
	realselect[0].selectedIndex = $(this).find('span.index').text();

	// update the pseudo selected element
	enhanced.find('.dropdown_toggle').empty().append('&lt;span&gt;&lt;/span&gt;').find('span').text($(this).find('span.value').text());

	return false;
});</code></pre>
<p>Here, we bind to the click event of each child anchor of a parent with a class of &#8216;options&#8217;. Upon click, we&#8217;re going to hide the visible parent (only one will be visible), determine the parent-most element (to which we added the &#8216;enhanced&#8217; class), and find the associated <code>select</code>. Once we&#8217;ve found the select, we can set the proper index to ensure accurate data translation using the hidden <code>span</code> we included in earlier steps. Finally, we&#8217;ll go ahead and update the copy within our enhanced <code>select</code>.</p>
<h3>Done and done? Not quite&#8230;</h3>
<p>The issue with <code>z-index</code> wasn&#8217;t something I initially thought of, it was something I only discovered as I was working. There were a number of additional speed bumps I ran into, which are terribly important as well. As it stood, interaction with the updated <code>select</code> was operating as expected, save for a passive action I originally overlooked. The trouble was with the toggle. In and of itself, the toggle was working as it should, but it was other interaction causing some trouble. For example, if your reader were to toggle open the options of your select, and then move elsewhere in the document without first closing the display of the options by again clicking the toggle, the list would remain in view.</p>
<p>This issue is easy enough to overcome. Prior to finding and looping through all of the <code>selects</code> in the document, you&#8217;ll need to bind to another event:</p>
<pre class="sh_javascript"><code>$(document).mousedown(checkExternalClick);</code></pre>
<p>Binding to the mousedown event for the entire document will fire the <code>checkExternalClick</code> function:</p>
<pre class="sh_javascript"><code>checkExternalClick = function(event)
{
	if ($(event.target).parents('.activedropdown').length === 0)
	{
		$('.activedropdown').removeClass('activedropdown');
		$('.options').hide();
	}
};</code></pre>
<p>What this function does is force any open option lists to hide should the reader click outside our new and improved <code>select</code>. It uses a conditional to check for the <code>class</code> we added during the original toggle, as to not interfere with any other functionality that may have been put in place.</p>
<p class="single_link"><a href="http://mondaybynoon.com/examples/custom-select/step-3/">View Step 3</a> (note: form submission <strong>is functional</strong>)</p>
<p>All together, our JavaScript looks like this:</p>
<pre class="sh_javascript"><code>var z = 999;

checkExternalClick = function(event)
{
  if ($(event.target).parents('.activedropdown').length === 0)
  {
    $('.activedropdown').removeClass('activedropdown');
    $('.options').hide();
  }
};

$(document).ready(function()
{
  $(document).mousedown(checkExternalClick);

  $('select').each(function()
  {
    if(!$(this).parent().hasClass('enhanced'))
    {
      targetselect = $(this);
      targetselect.hide();

      // set our target as the parent and mark as such
      var target = targetselect.parent();
      target.addClass('enhanced');

      // prep the target for our new markup
      target.append('&lt;dl class=&quot;dropdown&quot;&gt;&lt;dt&gt;&lt;a class=&quot;dropdown_toggle&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;/dt&gt;&lt;dd&gt;&lt;div class=&quot;options&quot;&gt;&lt;ul&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/dd&gt;&lt;/dl&gt;');
      target.find('.dropdown').css('zIndex',z);
      z--;

      // we don't want to see it yet
      target.find('.options').hide();

      // parse all options within the select and set indices
      var i = 0;
      targetselect.find('option').each(function()
      {
        // add the option
        target.find('.options ul').append('&lt;li&gt;&lt;a href=&quot;#&quot;&gt;&lt;span class=&quot;value&quot;&gt;' + $(this).text() + '&lt;/span&gt;&lt;span class=&quot;hidden index&quot;&gt;' + i + '&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;');

        // check to see if this is what the default should be
        if($(this).attr('selected') == true)
        {
          targetselect.parent().find('a.dropdown_toggle').append('&lt;span&gt;&lt;/span&gt;').find('span').text($(this).text());
        }
        i++;
      });
    }
  });

  // let's hook our links, ya?
  $('a.dropdown_toggle').live('click', function()
  {
    var theseOptions = $(this).parent().parent().find('.options');
    if(theseOptions.css('display')=='block')
    {
      $('.activedropdown').removeClass('activedropdown');
      theseOptions.hide();
    }
    else
    {
      theseOptions.parent().parent().addClass('activedropdown');
      theseOptions.show();
    }
    return false;
  });

  // bind to clicking a new option value
  $('.options a').live('click', function(e)
  {
    $('.options').hide();

    var enhanced = $(this).parent().parent().parent().parent().parent().parent();
    var realselect = enhanced.find('select');

    // set the proper index
    realselect[0].selectedIndex = $(this).find('span.index').text();

    // update the pseudo selected element
    enhanced.find('.dropdown_toggle').empty().append('&lt;span&gt;&lt;/span&gt;').find('span').text($(this).find('span.value').text());

    return false;
  });
});</code></pre>
<p class="single_link"><a href="http://mondaybynoon.com/examples/custom-select/step-3/">View Step 3</a> (note: form submission <strong>is functional</strong>)</p>
<h3>Almost perfect, but not quite</h3>
<p>I post this example not to propose the best possible solution for progressively enhancing <code>select</code> elements. There are some issues which still need attention, that browser default <code>form</code> widgets better handle out of the box. Such things as rendering the list of <code>options</code> within the viewport should the <code>select</code> be positioned too close to the bottom. We didn&#8217;t cover that scenario, but it&#8217;s something that can be easily overcome using jQuery and a couple conditionals.</p>
<p>While it was great working on a small technique such as this, it really got me thinking about the viability of such a thing. Interface design is a sensitive subject for me, and messing with such standard conventions as browser &amp; operating system interface elements felt wrong on a low level. On the contrary, the stock form widgets shipping with browsers today aren&#8217;t the most gorgeous thing to include in your designs. Would you consider drastically changing the appearance of your <code>form</code> elements?</p>
]]></content:encoded>
			<wfw:commentRss>http://mondaybynoon.com/2009/02/23/creating-custom-form-elements-using-jquery-selects/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
	</channel>
</rss>

<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Page Caching using disk (enhanced) (user agent is rejected)
Database Caching 6/15 queries in 0.009 seconds using disk

Served from: mondaybynoon.com @ 2010-09-06 10:57:25 -->