jQuery, Dynamic HTML and Dealing With eForms of Indeterminate Size.

Saturday, January 02 2010

jQuery, Dynamic HTML and Dealing With eForms of Indeterminate Size.

While waiting for more feedback from the team for my SiteFinity Project, I thought I would share some valuable discoveries in using jQuery to develop a Web Client eForm.  For those of you who are writing client-side Web code, if you haven’t already discovered jQuery, then you’re making your job much harder than it needs to be.   This post will attempt to give you a peek at the power and flexibility of this JavaScript library to solve a fairly common issue in web based application design – building a form that is capable of handling multiple details lines (e.g. lines of details on an invoice) without the performance penalties of static hidden HTML, and which can grow to handle almost unlimited rows. We’ll include late binding of events and validations as well.  All of this capability will be built into a simple HTML form with no code behind pages or server code.  When we are complete, you’ll have a great template to add to your toolbox.

The requirements, scope,  and solution:

The requirement for this project is one you’ve probably seen many times.  We need a web form that is capable of handling many detail lines for a single header which defines the one-to-many relationship between the header and its details.  Simple examples of this type of form would be online order forms, invoices, statements and the like.  The form must handle any number of details, whether one or hundreds, as efficiently as possible. What we will not be addressing in this Blog is the retrieval or the posting of the data.  That part of the project would be highly dependent upon the resources in the environment for which it is being developed and will be outside of what we are building here. 

The Strategy:

imageBy definition,the requirement to handle an indeterminate number of details as efficiently as possible, means that we will not be using static hidden rows of HTML which are “turned on” by setting their visibility properties.  Rather, we will be:

  1. Building a simple form with a header block, totals section, and a detail row template.
  2. Creating a JavaScript library of routines needed for basic form handling, validation, event binding etc.
  3. Binding an event to a button that allows us to:
      1. Select the HTML of our Row Template
      2. Inject the HTML into a details section of the form dynamically
      3. Bind events to the elements of the dynamic rows so that they self validate, format and total.
  4. Then we’ll wrap it all up into a small web application.

That’s a lot of ground to cover, so let’s get started. 
 

Building a simple form with a header block, totals section, and a detail row templateERLayout

To keep this example as simple and generic as possible, I will be creating a very simple HTML file.  The layout (at the right) is a header section, line detail section, and total section.  I have chosen table elements for this form because the data represented is inherently tabular. The actual HTML will show some additional layout which is hidden.  The line detail section is made up of two parts, one of which is displayed when the section is expanded, and one of which is displayed when the section is collapsed (default).  The intention is to allow the user to determine whether they prefer to enter details in the expanded or table sections of the form.  There are a few graphics added for buttons to make the application a little more appealing.  In the editor, the rendering of the HTML would appear like shown at the right.

Not shown at the right is the hidden tbody element ‘tRow_0’ that is the template for the row. 

 

jQuery Selectors, CSS, Element IDs  and Classes – Planning Tight Code.

The most important aspect of jQuery to master is the ‘selector’.  It’ allows us to group DOM elements and apply appearances and/or behaviors to the group and apply or change them ‘on-the-fly’.  This post is not intended to be a basic introduction to jQuery, but a quick overview is that jQuery which is usually called by it’s alias ‘$’ can use pattern matching, including regular expressions, to build a collection of DOM elements to which we will apply a property or behavior.  A selector would look like this:  $("#details input[id$=" + elemMask + "][value!=''].currencyInp").each(function(). 

With this selector, I am calling jQuery($) and passing it the string between the parenthesis.  The request sent to jQuery asks that all input elements within the DOM element with an ID of “Details” which match a dynamically generated mask “elemMask”, have a value that is not empty, and which have a CSS class of ‘.currencyInp’ be collected and passed to whatever function is defined in the following JavaScript block.  If you didn’t follow that summary, I suggest you take a little break and visit the jQuery site to familiarize yourself with jQuery.  If you caught the trick employed to avoid dealing with empty cell values when performing functions like adding and subtracting, you’re already starting to realize the value of jQuery as a tool.  

This selector of DOM elements represents a huge savings in efforts of the developer.  Additionally, by understanding and applying this capability you exercise significant control over the client with a minimum of added code – that equates to a better user experience without the performance penalty of ‘code bloat’. 

Included References and Files. 

As is the standard,  I’ve included the references to the supporting CSS and Script files in the header of the HTML

<head> 

<link href="css/EFormBase.css" rel="stylesheet" type="text/css" />
<link href="css/SampleForm.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" language="javascript" src="scripts/jquery-1.3.2.js"></script>
<script src="scripts/jquery-1.3.2-vsdoc.js" type="text/javascript"></script>
<script src="scripts/EFormBase.js" type="text/javascript"></script>
<script type="text/vbscript" language="vbscript" src="scripts/SampleForm.vbs"></script>
<script type="text/javascript" language="javascript" src="scripts/SampleForm.js"></script>

 </head>

 

 To summarize the files and their purpose, the “EFormBase” files are predominantly used to apply the validation engine to the onSubmit event of the Form and provide some default CSS appearances. 

The 2 “jQuery-1-3-2” files are the jQuery libraries and interface to my development environment.

The “SampleForm.vbs” and “SampleForm.js” files are the scripts that give life to the form.

 

Element IDs, CSS classes and a strategy to minimize code.

 A quick look at our form, and we can see that as the number of detail rows grow, the need to optimize the code of the template becomes more critical both to the performance of the form SampleZonesand to the amount of coding that must be created and supported.  Because we have chosen to template the row HTML and inject it into the form at run-time on the client as needed,  we avoid the bandwidth overhead of downloading all of the HTML that would be caused by many rows.  In addition, careful considerations was given to the element IDs and CSS classes to minimize the code needed to handle the appearance and behavior of the elements.  For the table section of the form, which exists entirely in the row template, the column name is added to the row number in a was that is easily and reliably separable.  In this case my cell IDs are in the form of ‘ColumnName_Row”.  The illustration shows how the form has been divided into zones based on behavior and appearance. 

The section circled in red and filled with light red are all currency input elements.  They share both appearance and behavior, and as we will see later this behavior includes the ability to self total and format.  The light blue filled text inputs in this region do not share the CSS class.

The section circled in dark blue is somewhat different.  Each column has its own appearance, behavior and validation, and so, while the CSS classes are shared across rows, each column has its own  class.

The total column and row each have their own class, but are read-only because they are handled entirely in code.

The other elements of the form also rely heavily on CSS but our focus during this post is the table details section of the form.

An Overview of SampleForm.js – Gluing Things Together.

We won’t be going through a line-by-line discussion of the code, but I hope to provide enough of an overview to make it easy to read the code and figure things out.  The first thing to notice is the ‘loadme()’ function which is bound to the onload event of the form. The particular line of interest is the $('#btnLineAdd').bind('click', function(event).

 

This nugget of jQuery code binds the addRow function to the green button element with an ID of ‘btnLineAdd’.  The addRow function, when triggered by this element, determines the next available row number, selects the HTML from the tbody ‘tRow_0’ element (our row template), replaces the row number ‘0’ with the row number being inserted, injects the code into the DOM form at the end of the detail section (jQuery append) then calls the function ‘bindThisRow(curRow)’ to bind the events for the elements of the row.  A study of the bind statements and the selectors will explain which elements are selected and which events are bound to them.  After the events are bound, we apply a little of the magic from the EFormBase.js file.  A deep dive into that code is beyond this  post. However, a quick explanation is that a validation engine is created and bound to the elements based on the column name portion of the element ID (e.g. Entity_1 would be validated based on the ‘Entity’ portion of the ID.)  This represent a significant savings in code and effort.  Properties for validation are configured through prototypes and instantiated upon creation.  By the time we have returned from the addRow function, we have injected a dynamically created HTML row, attached events, and added a validation engine.  All this was done with an surprisingly small code footprint.

A Summary and Encouragement.

So that wraps up this post and hopefully I’ve demonstrated enough of the jQuery goodness to encourage you to take the time to learn the tool and become comfortable with it.  Just the time saved in coding of this form would be enough to justify the time spent in the learning curve.  The future time savings when modifying or troubleshooting this form would be ‘frosting’.  As always, I welcome comments or suggestions.  Be kind.  This wasn’t intended to be a ‘textbook example’ or the best possible.  It’s just a sample I wanted to share to help make the learning and building of a little reusable code easier.  I hope this helps … let me know.

To learn more about jQuery.

Code Sample Here

1 comment(s)