WebgrownSolutions

William J. Familia's Dev Garden

Ajax Form + HTML5 Feature Support

As part of a new UI library, I have created a full-featured, HTML5-enhanced Ajax Form framework in a manner that follows the guidelines found in the Webgrown Solutions UI Manifesto. The Ajax Form supports the following features:

The Demo

Form Test #1 (Sign In) - Horizontal Layout

HINT: By entering "" for the username and "demo123" for the password, the JSON data returned will come back with a status of "Valid".

Form Test #2 (Add Person) - Vertical Layout

HINT: By entering "William" for the first name and "Familia" for the last name, the JSON data returned will come back with a status of "Duplicate".

The Markup

The form consists of just basic form fields (<input>, <select>, etc) and corresponding <label>s for the flexible layout. The button decorated with the "ajaxFormPost" class attribute and some custom data (data-*) attributes is all that is needed to enable the Ajax call. The "data-formGroup" custom data attribute is what ties the fields with the button (think ValidationGroup in ASP.NET). No <form> tag is required for the grouping, which works great with ASP.NET Web Form's single server form limitations. The "data-parameterName" custom data attribute on the form field is what maps each form field to its related service call parameter. The only scripting to be added for each form would be any "success" actions to be performed with the JSON data returned by the service call. That is it! Once the CSS and Script stuff are in place on a website, any page can take advantage of this full-featured Ajax Form by simply setting the button's class attribute and setting the needed button and form field custom data attributes. And don't forget, this gives you HTML5 form feature support ("placeholder", "autofocus", "required", and "pattern") on every browser, regardless as to whether the browser natively supports this new HTML5 feature or not. That means form validation ("required" and "pattern") is built in, with no additional scripting.

That sounds like a DRY solution to me (see UI Manifesto).

<h3>Form Test #1 (Sign In) - Horizontal Layout</h3>
<div class="form legendLook horizontalFormLayout">
    <div id="hdivFormTest1ConfirmationMessage" class="confirmationMessageWrapper hide"></div>
    <div id="hdivFormTest1ErrorMessage" class="errorMessageWrapper hide"></div>

    <label for="txtUsername">Username:</label>
    <input type="text" id="txtUsername" placeholder="E-mail Address" required autofocus 
        data-formGroup="formAuthenticate" 
        data-parameterName="username" />

    <label for="txtPassword">Password:</label>
    <input type="password" id="txtPassword" placeholder="e.g. demo123" required 
        data-formGroup="formAuthenticate" 
        data-parameterName="password" />

    <div class="formButtonWrapper clearFix">
        <input type="submit" class="ajaxFormPost buttonStrong" value="Sign In"
            data-formGroup="formAuthenticate" 
            data-serviceRequestUrl="/WebServices/AjaxFormTestClientService.svc/Authenticate" 
            data-successFunction="successFormTest1"
            data-confirmAction="false"
            data-confirmActionMessage=""
            data-processingMessage="signing in..."
            data-overlayWindowWhileProcessing="true" />
    </div>

    <p>HINT: By entering "" for the username and "demo123" for the password, the JSON data returned will come back with a status of "Valid".</p>
</div>

<h3>Form Test #2 (Add Person) - Vertical Layout</h3>
<div class="form legendLook">
    <div id="hdivFormTest2ConfirmationMessage" class="confirmationMessageWrapper hide"></div>
    <div id="hdivFormTest2ErrorMessage" class="errorMessageWrapper hide"></div>

    <label for="txtPersonFirstName">First Name:</label>
    <input type="text" id="txtPersonFirstName" required 
        data-formGroup="formAddPerson" 
        data-parameterName="FirstName" />

    <label for="txtPersonMiddleName">Middle Name:</label>
    <input type="text" id="Text1"
        data-formGroup="formAddPerson" 
        data-parameterName="MiddleName" />

    <label for="txtPersonLastName">Last Name:</label>
    <input type="text" id="txtPersonLastName" required
        data-formGroup="formAddPerson" 
        data-parameterName="LastName" />

    <label for="txtPersonCity">City:</label>
    <input type="text" id="txtPersonCity" required 
        data-formGroup="formAddPerson" 
        data-parameterName="City" />

    <label for="ddlPersonStateAbbreviated">State:</label>
    <select id="ddlPersonStateAbbreviated" required 
        data-formGroup="formAddPerson" 
        data-parameterName="StateAbbreviated">
		<option value="">Please select a state...</option>
		<option value="AL">Alabama</option>
		<option value="AK">Alaska</option>
		<option value="AS">America Samoa</option>
		<option value="AZ">Arizona</option>
		<option value="AR">Arkansas</option>
		<option value="AA">Armed Forces - Americas (AA)</option>
		<option value="AE">Armed Forces - Europe (AE)</option>
		<option value="AP">Armed Forces - Pacific (AP)</option>
		<option value="CA">California</option>
		<option value="CO">Colorado</option>
		<option value="CT">Connecticut</option>
		<option value="DE">Delaware</option>
		<option value="DC">District of Columbia (DC)</option>
		<option value="FL">Florida</option>
		<option value="GA">Georgia</option>
		<option value="HI">Hawaii</option>
		<option value="ID">Idaho</option>
		<option value="IL">Illinois</option>
		<option value="IN">Indiana</option>
		<option value="IA">Iowa</option>
		<option value="KS">Kansas</option>
		<option value="KY">Kentucky</option>
		<option value="LA">Louisiana</option>
		<option value="ME">Maine</option>
		<option value="MD">Maryland</option>
		<option value="MA">Massachusetts</option>
		<option value="MI">Michigan</option>
		<option value="MN">Minnesota</option>
		<option value="MS">Mississippi</option>
		<option value="MO">Missouri</option>
		<option value="MT">Montana</option>
		<option value="NE">Nebraska</option>
		<option value="NV">Nevada</option>
		<option value="NH">New Hampshire</option>
		<option value="NJ">New Jersey</option>
		<option value="NM">New Mexico</option>
		<option value="NY">New York</option>
		<option value="NC">North Carolina</option>
		<option value="ND">North Dakota</option>
		<option value="OH">Ohio</option>
		<option value="OK">Oklahoma</option>
		<option value="OR">Oregon</option>
		<option value="PA">Pennsylvania</option>
		<option value="PR">Puerto Rico</option>
		<option value="RI">Rhode Island</option>
		<option value="SC">South Carolina</option>
		<option value="SD">South Dakota</option>
		<option value="TN">Tennessee</option>
		<option value="TX">Texas</option>
		<option value="UT">Utah</option>
		<option value="VT">Vermont</option>
		<option value="VI">Virgin Islands</option>
		<option value="VA">Virginia</option>
		<option value="WA">Washington</option>
		<option value="WV">West Virginia</option>
		<option value="WI">Wisconsin</option>
		<option value="WY">Wyoming</option>
	</select>
    <!-- I know having two columns for the full name and abbreviated name for a state is not normalized and a bad idea, 
    but this is just for testing purposes to see how to massage the form as needed before the submit.  -->
    <input id="hfPersonState" type="hidden" 
        data-formGroup="formAddPerson" 
        data-parameterName="State" />

    <label for="txtPersonZipCode">Zip Code:</label>
    <input type="text" id="txtPersonZipCode" class="postalCodeTextbox"   
        required
        placeholder="ZIP or ZIP+4"
        data-allowExtended="true"
        data-formGroup="formAddPerson" 
        data-parameterName="ZipCode" />

    <div class="formButtonWrapper">
        <input type="submit" class="ajaxFormPost buttonStrong" value="Add Person"
            data-formGroup="formAddPerson" 
            data-serviceRequestUrl="/WebServices/AjaxFormTestClientService.svc/AddPerson" 
            data-parameterObjectName="person" 
            data-successFunction="successFormTest2" />
    </div>

    <p>HINT: By entering "William" for the first name and "Familia" for the last name, the JSON data returned will come back with a status of "Duplicate".</p>
</div>

The CSS

Not shown to the general public.
        

The Script

Not shown to the general public.
        
blog comments powered by Disqus

In addition to the markup, CSS, and JavaScript code samples found below the demo, the following resources/files are required:

We are processing your request.

loading...
*
Please fix the following issues and then submit again: is required. is not valid. does not match
loading...
mm/dd/yy mm/dd/yy 0 Previous Next ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'] ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'] ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'] ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'] Wk false false false h:mm tt Choose Time Time: Hour: Minute: Second: Now Done You have # character(s) remaining.