MonoRail - Efficient Tab Indexing

I'm a big fan of keyboard shortcuts for the Windows, Resharper, Firefox, Web Browsing, GMail, etc.  The less I touch the mouse the more productive I am.  One thing that can make a great web application suck hard is poor or absent tab indexing on form fields.  It takes a little extra time on the developers part but it makes a world of difference to the end user.  Rather than hard code tabIndexes, I use the following technique using a simple accumulator:

<?brail
  tabIndex = 1
?>

${Form.FormTag({'action':'login'})}
<table>
  <tr>
    <td>${Form.LabelFor('username', 'Username')}</td>
    <td>
      ${Form.TextField('username', {'tabIndex':tabIndex++})}
    </td>
  </tr>
  <tr>
    <td>${Form.LabelFor('password', 'Password')}</td>
    <td>${Form.PasswordField('password', {'tabIndex':tabIndex++})}</td>
  </tr>
  <tr>
    <td />
    <td>${Form.Submit('Login', {'tabIndex':tabIndex++})}</td>
  </tr>
</table>
${Form.EndFormTag()}

One problem I struggled with in ASP.Net was allowing tabIndexes to properly flow from a page to a user control then back again.  I'm going to ping Oren to see if it is possible to declare tabIndex 'globally' (in a layout maybe?) and allow all views/sub views/view components to use the same value to try and address this in MonoRail.

Dexagogo - Alert Validation Advice

I recently blogged about using Dexagago validation API with MonoRail.  The API allows you to specify your own advice messages in any HTML element.  The framework will take care of showing/hiding the element as needed during validation.  I wanted to be able to display a javascript alert box with validation messages in certain cases.  Here's what I came up with:

<script type="text/javascript">
  function AlertAdvice(isValid, el)
  {
    if( !isValid )
    { 
      alert(el.title);
      if(el.select) el.select();
    }
  }
</script>

${Form.FormTag({'action':'login','immediate':'false','stopOnFirst':'true','onElementValidate':'AlertAdvice'})}
<table>
  <tr>
    <td>${Form.LabelFor('username', 'Username')}</td>
    <td>
      ${Form.TextField('username', {'class':'required','title':'Please enter a Username'})}
      <div id="advice-username" style="visibility: hidden;" />
    </td>
  </tr>
  <tr>
    <td>${Form.LabelFor('password', 'Password')}</td>
    <td>${Form.PasswordField('password', {'class':'required'})}</td>
  </tr>
  <tr>
    <td />
    <td>${Form.Submit('Login')}</td>
  </tr>
</table>
${Form.EndFormTag()}

First we specify a javascript function 'AlertAdvice' that will be called by the validation API for each validator on our form.  If the validator fails (empty required field, alpha in a numeric field, etc) we display the contents of the title attribute, then for good measure we select the contents of the field.  When specifying your form tag you want to make sure to set immediate to false.  I found this out the hard way (took me a few tries :) otherwise you will be locked in a tight loop with a constant alert on invalid fields.  I also set stopOnFirst to true so that the user doesn't get overwhelmed with prompts for a large number of invalid fields.  Finally, we hook up our AlertAdvice function with the onElementValidate property.

You need to put the message you want displayed in the prompt in the title attribute of your field, ${Form.TextField('username', {'class':'required','title':'Please enter a Username'})} in our example above.  Finally, I wasn't able to find a way to disable the API's automatic display of an advice message.  To work around this, I add a hidden div element with a name of advice-<fieldName>. 

Lightly tested in IE6 and FF2.

«June»
SunMonTueWedThuFriSat
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567