Web Form 2.0 - Part 4

This post is part of a series and will make more sense if you read the earlier posts:

To make our form nicer to use I want to add a little AJAX to display the names and prices of products as the user enters them into the form.  To do this I have added two new columns which the user will not be able to edit:

    <tbody>

        <tr>

            <td><input type="text" name="code" /></td>

            <td><span class="name"></span></td>

            <td><span class="price"></span></td>

            <td><input type="text" name="quantity" /></td>

        </tr>

    </tbody>

Returning Data With Json.NET

The next thing we are going to need is a way to query the server for the details of a given product.  To keep things nice and simple I've written an ASPX page which returns a product using JavaScript Object Notation.  The product is defined on the server by a simple .Net class:

    public class Product

    {

        public string Code { get; set; }

        public string Name { get; set; }

        public decimal Price { get; set; }

    }

I've hard coded a few products for my example but GetProduct could fetch this data from a database, web service or any other source.  Serializing a product ready for JavaScript to use is as simple as a single call using the Json.NET library:

    protected void Page_Load(object sender, EventArgs e)

    {

        string code = Request.QueryString["code"];

        Product product = GetProduct(code);

 

        Response.Write(JavaScriptConvert.SerializeObject(product));

        Response.End();

    }

JSON is a nice human readable format so you can test the page easily by browsing to it's URL:

JsonQuery

Simple AJAX With jQuery

Included in the jQuery library is a set of functionality for performing AJAX calls with support for JSON data.  We will use this functionality in an event that fires whenever the users focus leaves the code column of the form.  To set up the event we add a few lines to our existing ready function:

    $('[name=code]')

    .blur(function(e) {

        GetProduct(e.target);

    });

We pass e.target through to the function as it will be the input control that has just lost focus.  When the event fires we use the getJSON function to call the server and ask it for details about the code the user entered:

    function GetProduct(input) {

        $.getJSON(

            'ProductQuery.aspx?' + $(input).serialize(),

            function(product) {

                UpdateRow(input.parentNode.parentNode, product);

            }

        );

    }

The first parameter passed is the URL to which the AJAX call will be made.  serialize is another jQuery helper which formats the input value into a query string parameter for us.

The second parameter we pass is a function that will be called when the AJAX query completes.  Because we have asked jQuery for JSON data the results of the query will be read into a JavaScript object ready for us to pass to the UpdateRow function.

    function UpdateRow(tr, product) {

        var name = $('.name', tr);

        var price = $('.price', tr);

 

        if(product != undefined) {

            name.html(product.Name);

            price.html(product.Price);

        }

        else {

            name.html('Not Found');

            price.html('');

        }

    }

This function simply finds the name and price fields from the same row and populates them with the product data we received from the AJAX call.  That's all there is to it!

Conclusion

This is the final part in this series so I have compiled and uploaded the example order form with all of the functionality we have covered:

The source project was created with Visual Studio 2008 and should include everything you need to build and run.  The test page contains 3 hard coded products which you can find by entering the codes 123, 456 and 789.

The code is intended to be an example only so there is a lot more to be done but you are welcome to use it as a reference or base for your own work.  Hopefully it demonstrates a few techniques you can use to improve you own sites.

Labels: , , ,

16/05/2008 05:03 AM (UTC -07:00)

Web Form 2.0 - Part 3

This post part of a series and will make more sense if you read the earlier posts:

jQuery

In this post I want to start working on the client side interactivity for our example form.  To do this I am going to use a JavaScript library called jQuery.  The homepage for the library has the following description:

jQuery is a fast, concise, JavaScript Library that simplifies how you traverse HTML documents, handle events, perform animations, and add Ajax interactions to your web pages. jQuery is designed to change the way that you write JavaScript.

The library makes JavaScript programming much more enjoyable and can be as small as 15kb for the user to download (assuming a minified, Gzipped library).  I'm going to use jQuery in my example and provide a brief explanation but for learning the library in more depth you can start by referring to the documentation and tutorials on their site.

To get started we need to include the library in our page.  I have also added a file for my own JavaScript code.

    <head runat="server">

        <title>Examples - Order Form</title>

        <script src="jquery-1.2.3.min.js" type="text/javascript"></script>

        <script src="OrderForm.js" type="text/javascript"></script>

    </head>

Adding Rows Dynamically

As I hinted at in the previous post I am going to provide a way to add rows to the form dynamically so that we do not have to guess how many items the user wants to order.  The basic idea is to provide a template row that will be cloned when we want to create more rows.  The following JavaScript provides a simple implementation of this:

    var tbody;

    var template;

 

    function AddRows(count) {

        for(var i = 0; i < count; i++) {

            tbody.append(template.clone());

        }

    }

 

    $(document).ready(function() {

        tbody = $('tbody');

        template = $('tr', tbody).clone();

        AddRows(4);

    });

The first thing to understand about jQuery is that it extends objects with a lot of useful functionality such as the clone function we are using.  The most common way to get an object with this additional functionality added is using the global syntax which uses the same syntax as CSS to locate objects in the HTML DOM:

    tbody = $('tbody');

You can also use other CSS selectors such as a period to select items by class or has to select items by ID.  This is very powerful and deals with all of the cross browser compatibility issues for you.

The ready function registers for an event that will fire when the page is loaded and the table is ready to be modified.  In our ready function we locate the tables body and the row that is described in the HTML.  We use the clone method to make our own copy of the row and store it away for later.  We then call the AddRows function to add another 5 rows to our initial form.

The AddRows function simply loops the requested number of times and uses the jQuery append function to add another clone of our template row to the tables body.

Wiring It Up

Other than linking to the JavaScript files in the head tag we have added dynamic rows to our form without modifying the HTML in any way.  The JavaScript files should be downloaded once and cached which gives us a nice saving in bandwidth as a bonus.

We can now provide a button on our form for the user to add as many rows to the form as they like:

    <input type="button" id="addRows" value="Add Rows" />

To keep functionality nicely separated from my markup I'm going to add code to the ready function which wires up the call to AddRows:

    $(document).ready(function() {

        $('#addRows').click(function() {

            AddRows(5);

        });

        ...

We use the ID of the input tag to locate it as there is only one.  click is an event that jQuery will call for us when the button is clicked and each time it will call our AddRows function adding another 5 rows to the table.

Next Time

As you can see with a basic knowledge of JavaScript it requires very little code to improve a form a great deal.  Next time I will look at doing something a little more advanced and use jQuery's AJAX to provide feedback on the codes that the user is entering.

Labels: , , ,

04/05/2008 04:01 AM (UTC -07:00)

Web Form 2.0 - Part 2

This post is a continuation of Web Form 2.0 - Part 1 so I suggest you read that before continuing here.  The previous post has the introduction so let's get right to it.  Normally when creating an ASP.Net form we enter markup like this:

    <asp:TextBox ID="txtCode" runat="server" />

When the user posts the form back to the server we can use the text the user entered like this:

    DoSomething(txtCode.Text);

In Part 1 I put together a simple HTML form without using the ASP.Net text box controls but because I haven't marked these controls with a runat attribute they will not be accessible from our code behind.

    <input type="text" name="code" />

    <input type="text" name="quantity" />

How then will I be able to access the values contained in these controls?  All of the form values that were passed with the request are available through the ASP.Net Request object:

Request

As you can see even the hidden input field that contains the encrypted view state is available!  The key being used in the value of the name attribute that you put on the control.  All of the values will be passed as strings so we can use them like this:

    string code = Request.Form["code"];

    int quantity = Int32.Parse(Request.Form["quantity"]);

Our example order form is probably going to want more than one row, how will this information be passed back to the user?  Remember that we are using the controls name attribute to get the data.  Controls must have unique ID attributes but names can be shared which allows us to do this to get an array of all the codes entered:

    <input type="text" name="code" />

    <input type="text" name="code" />

    <input type="text" name="code" />

RequestMultiple

    string[] codes = Request.Form["code"].Split(',');

This way we do not need to know how many rows there actually were in the table or try and figure out which ID to use to find all of the codes.  You will need to be careful what input you allow as entering a comma into a code field will cause problems.  If necessary you can generate unique names for the controls like this:

    <input type="text" name="code1" />

    <input type="text" name="code2" />

    <input type="text" name="code3" />

This will mean that you no longer get all the values in a comma separated list and will need to access them individually by their generated name.

Next time I will be looking at how to use JavaScript to generate forms with multiple rows without bloating your markup and using a lot of bandwidth, stay tuned.

Labels: , , ,

03/05/2008 07:56 PM (UTC -07:00)