Click here to Skip to main content
15,884,176 members
Articles / Web Development / HTML

Interactive Form Functionality on the Client-Side Using jQuery

Rate me:
Please Sign up or sign in to vote.
4.82/5 (6 votes)
3 Apr 2010CPOL5 min read 39.9K   855   37   1
Using jQuery and XML to create a simple, interactive client-side order form
jqueryform2.png

Introduction

Many of us have used ASP.NET Web Forms for years, combined more recently with ASP.NET AJAX, to build robust web-solutions for our clients. Although Web Forms are not going away, it is also not the only technology available to ASP.NET developers to build web-solutions, or necessarily always the best. A developer’s ability to understand and implement multiple development technologies is critical to ensuring the best solution for the client.

Recently, the popularity of serious client-side development with JavaScript, jQuery, and AJAX has exploded. Much of the server-side processing required with ASP.NET Web Forms can easily be moved to the client-side with the help of increasingly sophisticated scripting tools such as jQuery and Ajax. The following article demonstrates and discusses a simple client order form, built using HTML, JavaScript, jQuery, AJAX, XML, and CSS. This example demonstrates many basic as well as some advanced capabilities of jQuery, including:

  • Asynchronous HTTP (Ajax) request to populate a dropdown menu with XML data
  • jQuery animation and CSS manipulation to enhance the client UI experience
  • Use of jQuery plug-ins, specifically FormatCurrency to format text
  • JavaScript and CSS minification to increase performance and obfuscate client-side code
  • Use of Content Delivery Networks (CDN) to further optimize performance through web caching

In this example, a user individually chooses products from a dropdown menu, inputs the desired quantity, and adds the selection to their order. The selections along with a subtotal of their costs are displayed in the order table. Items can be removed from the order and additional items added. The order’s total cost is updated and displayed as items are added and removed. All events are handled on the client-side, without any server-side processing.

A working example of this form can be accessed here.

About the Code

The files which make up the web directory of the order form example are as follows: (2) versions of the HTML order form, (1) XML data file with menu items, (6) JavaScript files, and (2) versions of the Style Sheets. Shown below is the directory of those files as seen in Visual Studio 2008, and available for download at the top of this article.

Image 2

The order form example comes in two flavors – an easy-to-understand, development-oriented copy (order_dev.htm), and a production-oriented copy (order_prd.htm), optimized for faster web-serving. The development version has all my JavaScript left in the bottom of the HTML file. The Style Sheet, jQuery library and FormatCurrency jQuery plug-in scripts are externally linked to non-minified sources. Conversely, the production version has the Style Sheet and all JavaScript externally-linked to minified files. I created two versions of the order form in order to compare the effects of optimization techniques on web-serving performance.

Code Optimization and Obfuscation

Using CSS Drive’s CSS Compressor online utility, I decreased the size of my externally-linked Style Sheet file by 26%. I selected the ‘Super Compact’ and “Strip ALL Comments’ options. Using Google’s Closure Compiler online utility, I decreased the size of my JavaScript by 43%. I selected the ‘Simple’ Optimization option. The more aggressive ‘Advanced’ option resulted in JavaScript errors. I did not select a Formatting option. According to the results from Firefox using Yahoo! YSlow, externally linking to minified copies of my Style Sheet and JavaScript files reduced the total size of the information sent to the browser from 175.8K to 79.9K, a savings of nearly 55%.

You can further test page performance by replacing the local link to the jQuery script file with a link to the minified copy of jQuery on Google’s Content Delivery Network (CDN). The current link is commented out within order-prd.htm. For an explanation of the advantages and disadvantages of using a CDN, I recommend Dave Ward’s post on Encosia.com, entitled 3 reasons why you should let Google host jQuery for you.

HTML
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>

jQuery IntelliSense in Visual Studio 2008

The obvious advantage of keeping the JavaScript in the HTML page, at least during development, is the ability to take advantage of IntelliSense in Visual Studio 2008 with jQuery. IntelliSense makes the jQuery learning process much quicker! See a good post on this topic, jQuery Intellisense in VS 2008, by Scott Guthrie, at ScottGu’s Blog. Note, as of the date of publication of this article, the latest version of jQuery to have the necessary ‘-vsdoc’ file available for use with IntelliSense was version 1.4.1. I used this for the development version of the example. The production copy uses a later, minified version of jQuery 1.4.2, which is notably faster than 1.4.1.

Placing the Order

The form contains a button to place the final order. In this example, pressing the button returns a simple JavaScript alert(), depending on the contents of the order. In actual production, the order page could submit form data to a secondary page or code-behind class (ASP.NET Web Forms) for order processing. Alternatively, data could be formatted and sent directly back to an XML file or to a database using Ajax. Order processing could be done on the client- or server-side, depending on the technology implemented.

Using the Code

The order page contains two HTML tables. One table holds the menu selection elements and the other table displays the current order. Since jQuery so eloquently handles all interactions within the UI, there is very little HTML code to write.

HTML
<table id="select">
    <caption>
        Menu</caption>
    <tr>
        <td>
            Qnt.:
        </td>
        <td>
            <input id="select_quantity" type="text" /> (*1-99)
        </td>
        <td>
            <select id="select_item">
                <option selected="selected">Select an Item...</option>
            </select>
        </td>
        <td>
            <input id="add_btn" type="button" value="Add" />
        </td>
    </tr>
</table>
<br />
<br />
<table id="order_cart">
    <caption>
        Order</caption>
    <thead>
        <tr>
            <th>
                Qnt.
            </th>
            <th>
                ID
            </th>
            <th>
                Description
            </th>
            <th>
                Price
            </th>
            <th>
                Subtotal
            </th>
            <th>
                Remove
            </th>
        </tr>
    </thead>
    <tbody>
    </tbody>
    <tfoot>
        <tr>
            <th colspan="4">
                Total:
            </th>
            <th id="order_total">
                $0.00
            </th>
            <th>
                <input id="order_btn" type="button" value="Order!" />
            </th>
        </tr>
    </tfoot>
</table>

<script src="scripts/jquery-1.4.1.js" type="text/javascript"></script>

<script src="scripts/jquery.formatCurrency-1.3.0.js" type="text/javascript"></script>

The JavaScript contained in order_dev.htm immediately precedes the closing </body> tag. Keeping the JavaScript at the bottom of the page whenever possible allows the CSS and DOM elements to load first. I have included a large number of comments detailing much of the functionality contained in each part of the JavaScript.

JavaScript
<script type="text/javascript">
    //Retrieve XML document and loop for each item
    jQuery(function($) { //just like $(document).ready()
        $.ajax({
            type: "GET",
            url: "data/menu.xml",
            dataType: "xml",
            error: function() {
                $("<p>Error loading XML file...</p>")
                .replaceAll("#order_form")
            },
            success: function(xml) {
                $(xml).find("item").each(fWriteXML); //must call function as var
            }
        });
    });

    //Populate drop-down box with XML contents
    var fWriteXML = function writeXML() {
        var id = $(this).attr("id");
        var cost = $(this).attr("cost");
        var item = $(this).text();
        $("#select_item")
            .append($("<option></option>")
            .val(id) //same as .attr("value", id))
            .html(item)
            .attr("title", cost));
    };

    //Add selected item to order
    $(function() {
        $("#add_btn").click(function() {
            var order_item_selected_quantity = $("#select_quantity").val()
            var selected_item = $("#select_item option:selected");
            var order_item_selected_id = selected_item.val();
            var order_item_selected_name = selected_item.text();
            var order_item_selected_cost = selected_item.attr("title");

            var pattern = new RegExp("^[1-9][0-9]?$"); //Select between 1-99 items
            //Do not proceed if input is incorrect
            if (pattern.test(order_item_selected_quantity) &&
                order_item_selected_cost != "") {

                //Calculate subtotal
                var order_item_selected_subtotal =
                    parseFloat(order_item_selected_cost) *
                    parseInt(order_item_selected_quantity);

                $("<tr class='order_row'></tr>").html("<td>"
                    + order_item_selected_quantity + "</td><td>"
                    + order_item_selected_id + "</td><td class='order_item_name'>"
                    + order_item_selected_name + "</td><td class='order_item_cost'>"
                    + order_item_selected_cost +
            "</td><td class='order_item_subtotal'>"
                    + order_item_selected_subtotal + "</td><td>"
                    + "<input type='button' value='remove' /></td>")
                        .appendTo("#order_cart").hide();

                $("#order_cart tr.order_row:last").fadeIn("medium", function() {
                    orderTotal(); //Callback once animation is complete
                });

                //Format new order item values to currency
                $("#order_cart td.order_item_cost:last").formatCurrency();
                $("#order_cart td.order_item_subtotal:last").formatCurrency();

                clickRemove();
                clearForm();
            }
        });
    });

    //Bind a click event to the correct remove button
    function clickRemove() {
        $("#order_cart tr.order_row:last input").click(function() {
            $(this).parent().parent().children().fadeOut("fast", function() {
                $(this).parent().slideUp("slow", function() {   //the row (tr)
                    $(this).remove();   //the row (tr)
                    orderTotal();
                });
            });
        });
    };

    //Clear order input form and re-focus cursor
    function clearForm() {
        $("#select_quantity").val("");
        $("#select_item option:first-child").attr("selected", "selected");
        $("#select_quantity").focus();
    };

    //Calculate new order total
    function orderTotal() {
        var order_total = 0;
        $("#order_cart td.order_item_subtotal").each(function() {
            var amount = ($(this).html()).replace("$", "");
            order_total += parseFloat(amount);
        });

        $("#order_total").text(order_total).formatCurrency();

        //Create alternating colored rows in order table
        $("#order_cart tr.order_row:odd").css("background-color", "#F0F0F6");
        $("#order_cart tr.order_row:even").css("background-color", "#FFF");
    };

    //Pretend to place order if it contains items
    $(function() {
        $("#order_btn").click(function() {
            if ($("#order_cart tr.order_row:last").length == 0) {
                alert("No items selected...");
            }
            else {
                alert("Order placed...");
            }
        });
    });
</script>

Additional Resources

I highly recommend the following resources to both beginner and intermediate jQuery developers who want to learn more about this great client-side development tool:

History

  • March 31, 2010 - version 1.0
    • Initial version uploaded
  • April 4, 2010 - version 1.01
    • Minor modification to code - added clickRemove() function

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Paychex
United States United States
I am a senior software developer, architect, and project manager, specializing in .NET, JavaScript, Java, and database development, and build automation. I am currently a Lead Developer (.NET) / Developer IV for Paychex Enterprise Business Solutions. Paychex (PAYX) provides payroll, human resources, and benefits outsourcing and web-based solutions to business.

Prior to Paychex, I served as Lead Software Engineer, Operations Manager, and Technical Product Manager at Bio-Optronics. Bio-Optronics develops, deploys and operates information technology solutions to help healthcare professionals manage and optimize workflow to enhance quality, productivity, and patient and staff satisfaction and safety. Previously, I held positions of President, COO, Chief Technology Officer (CTO), and SVP of Technology for Lazer Incorporated. Lazer is a successful, digital imaging and Internet-based content management services provider.

Comments and Discussions

 
QuestionCan Something Similar Be Done with Gridview Selected Items? Pin
Sid Childers6-Apr-10 8:06
Sid Childers6-Apr-10 8:06 
Hi Gary,

Thanks for a great article. I'm working on a quote management system using ASP.NET 3.5 written in VB. Your article does the reverse of what I'm seeking. That is, I have a gridview containing search results from a parts table in my database. Inside the gridview, besides the fields from the table, I've also included a textbox inside a template field. The idea is that the user inputs the quantity into the textbox for an item they want quoted.

I've researched the idea of just sending selected rows to a second control on the same page (thinking Listbox, but not locked into that). However, the idea of using JQuery intrigues me as well. Is it advisable to use JQuery to retain the items the user selects (with quantities) while they search for parts?

Thanks again for an informative article. Your help and guidance in using JQuery to augment my quote page is much appreciated.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.