Archive for February, 2009

Introduction to jQuery Presentation

I just finished my Introduction to jQuery presentation at the NYC Web Design Meetup.  Thanks for all that attended.  We had a really good time and had lots of great questions.

Download

I’ve posted the presentation and demos online.

Intro to jQuery.zip

Note

I made some minor changes to the Google AJAX sample.  The sample shown at the meeting didn’t support repeated clicks of the Get Google Links button.

jQuery Tab View using AJAX and WCF REST Service

In response to a question on StackOverflow Master Details using jQuery Tabs I wrote little sample app to demonstrate using jQuery Tabs and a WCF REST Service to create a Master Details view of Orders. I decided I’d also reference the solution here and give a little bit of an overview of how the Sample works.

Download

Sample Project: jQuery-AjaxTabView-Sample.zip (194KB)

Default.aspx

The Default page is basically a UI Tab setup with a ListView on the first tab.  The ListView contains a table of Orders with a simple Select link.  Notice that the select button is not an asp hyperlink control.  If you don’t need the extra code-behind or rendering of the user control I avoid them.  But, back to the Default Page.  On the second tab I have to layers one for loading and one for results.  The results tab is preloaded with the default message of Select an order.

The other major function of the page is in the jQuery Scripting, but I’ll get into that later.  First let me explain the service.

WCF Orders Service

With the release of the WCF REST Starter Kit its become very simple to create a service that returns some simple JSON results.   In this sample I have a single service called Service.svc (OrderService might have been a better name, next time…).  The service has a standard WebServiceHost2 Factory definition (which you can view by opening the actual Service.svc file) and a single Service.svc.cs code-behind.  The Service contains two methods one to return all Orders and one to return a single Order’s Details

[ServiceContract]
[ServiceBehavior(IncludeExceptionDetailInFaults = true, InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Single)]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class OrderDetailsService
{
    [OperationContract]
    [WebGet(UriTemplate = "", ResponseFormat = WebMessageFormat.Json)]
    public IEnumerable GetOrders()
    {
        // todo: replace with real implementation
        return Order.GetStubData();
    }

    [OperationContract]
    [WebGet(UriTemplate = "{orderId}", ResponseFormat = WebMessageFormat.Json)]
    public List GetOrderDetails(string orderId)
    {
        // todo: replace with real implementation
        var orders = Order.GetStubData();

        // todo: handle bad orderIds
        var order = orders.FirstOrDefault(o => o.OrderId == int.Parse(orderId));

        if (order == null)
            return null;

        return order.Details;
    }
}

You can access http://localhost:{port}/Service.svc to get the Orders as a JSON list, or you can access http://localhost:{port}/Service.svc/1 to get the OrderDetails as a JSON list for Order #1.

jQuery Scripts

Now that you have the WCF Service setup you need to have jquery connect to the service and render the data out when it receives the results.  The basic steps are that occur when the Select button is clicked are:

  1. Call preventDefault to stop the link
  2. Update the Tab2 UI to Loading
  3. Select Tab 2
  4. Parse the OrderId from the Hash of the link
  5. call jQuery $.getJSON(‘Service.svc/{orderId}’, null, function(json) {  } );

When the you return from the getJSON call you need to:

  1. Check to determine that you got valid results
  2. Set error message if necessary
  3. Generate table of results
  4. Loop results creating a row for each result
  5. Reset UI to hide loading and show results

Now on to the actual script that handles this.  Keep in mind that all this code is inside a $(document).ready(), for the full implementation download the sample project.

$('.selectOrder').click(function(e) {
    e.preventDefault();

    //setup loading ui
    $('#tabs').tabs('select', 1);
    $('#tabs-2 .loading').show();
    $('#tabs-2 .results').hide().empty();

    var id = this.hash.replace("#Select_", "")

    $.getJSON("Service.svc/" + id, null, function(details) {
        details.length = details.length ? details.length : 0;
        if (details.length == 0) {
            $('#tabs-2 .results').append('<h3>No Order Details</h3>').show();
        }
        else {
            var table = $('<table />').attr('cellspacing', 0).attr('cellpadding', 4);

            var header = $(<tr />')
                .appendCell("Product")
                .appendCell("Quantity")
                .appendCell("Price")
                .appendCell("Cost")
                .addClass('header');
            table.append(header);

            $.each(details, function() {
                var row = $('<tr />')
                    .appendCell(this.Product)
                    .appendCell(this.Quantity)
                    .appendCell(this.Price)
                    .appendCell(this.Quantity*this.Price);
                table.append(row);
            });

            $('#tabs-2 .results').append(table).show();
        }

        $('#tabs-2 .loading').hide();
    });
});

Conculsion

I hope that you like this sample.  As with any full AJAX solution the real complication comes into play when we start trying to customize the design.  That being said I would recommend putting as much of the design into the css as possible and avoid putting to many styles in the javascript. 

Other things to note, this doesn’t work cross domain, in order to do cross-domain json you need to use jsonp (JSON with Padding).   JSONP can be accomplished through the use of WCF Extensions which is not covered in this article, for more information see this msdn article and this msdn forum post.  jQuery supports jsonp; you would change the getJSON call to $.getJSON(‘Service.svc/1?callback=?’), where callback is the name of the querystring parameter expected by the service, and jquery would recongnize the callback=? and handle all the dirty work for you.  Finally, there is no exception handling in this code.  I just set the length to 0 if I don’t find one.  WCF will actually return the Exception message in the json response.  The next iteration of this project would be to include exception handling in the results callback. 

Happy coding.

Very Simple Javascript State Matching

I created this simple little javascript state matching library and I was amazed at how simple it turned out being, so I had to post it.

I’m leveraging a javascript object as a Key/Value Pair lookup.

stateMatcher.js


var stateMatcher = {
    Names: { "":"", "ALASKA": "AK", "ALABAMA": "AL", "ARKANSAS": "AR", "ARIZONA": "AZ", "CALIFORNIA": "CA", "COLORADO": "CO", "CONNECTICUT": "CT", "DISTRICT OF COLUMBIA": "DC", "DELAWARE": "DE", "FLORIDA": "FL", "GEORGIA": "GA", "GUAM": "GU", "HAWAII": "HI", "IOWA": "IA", "IDAHO": "ID", "ILLINOIS": "IL", "INDIANA": "IN", "KANSAS": "KS", "KENTUCKY": "KY", "LOUISIANA": "LA", "MASSACHUSETTS": "MA", "MARYLAND": "MD", "MAINE": "ME", "MICHIGAN": "MI", "MINNESOTA": "MN", "MISSOURI": "MO", "MISSISSIPPI": "MS", "MONTANA": "MT", "NORTH CAROLINA": "NC", "NORTH DAKOTA": "ND", "NEBRASKA": "NE", "NEW HAMPSHIRE": "NH", "NEW JERSEY": "NJ", "NEW MEXICO": "NM", "NEVADA": "NV", "NEW YORK": "NY", "OHIO": "OH", "OKLAHOMA": "OK", "OREGON": "OR", "PENNSYLVANIA": "PA", "PUERTO RICO": "PR", "RHODE ISLAND": "RI", "SOUTH CAROLINA": "SC", "SOUTH DAKOTA": "SD", "TENNESSEE": "TN", "TEXAS": "TX", "UTAH": "UT", "VIRGINIA": "VA", "VERMONT": "VT", "WASHINGTON": "WA", "WISCONSIN": "WI", "WEST VIRGINIA": "WV", "WYOMING": "WY" },
    Abbreviations: { "": "", "AK": "Alaska", "AL": "Alabama", "AR": "Arkansas", "AZ": "Arizona", "CA": "California", "CO": "Colorado", "CT": "Connecticut", "DC": "DistrictofColumbia", "DE": "Delaware", "FL": "Florida", "GA": "Georgia", "GU": "Guam", "HI": "Hawaii", "IA": "Iowa", "ID": "Idaho", "IL": "Illinois", "IN": "Indiana", "KS": "Kansas", "KY": "Kentucky", "LA": "Louisiana", "MA": "Massachusetts", "MD": "Maryland", "ME": "Maine", "MI": "Michigan", "MN": "Minnesota", "MO": "Missouri", "MS": "Mississippi", "MT": "Montana", "NC": "NorthCarolina", "ND": "NorthDakota", "NE": "Nebraska", "NH": "NewHampshire", "NJ": "NewJersey", "NM": "NewMexico", "NV": "Nevada", "NY": "NewYork", "OH": "Ohio", "OK": "Oklahoma", "OR": "Oregon", "PA": "Pennsylvania", "PR": "PuertoRico", "RI": "RhodeIsland", "SC": "SouthCarolina", "SD": "SouthDakota", "TN": "Tennessee", "TX": "Texas", "UT": "Utah", "VA": "Virginia", "VT": "Vermont", "WA": "Washington", "WI": "Wisconsin", "WV": "WestVirginia", "WY": "Wyoming" }
};

Usage


var longName = stateMatcher.Abbreviations["NY"];
// or
var abbr = stateMatcher.Names["New York".toUpperCase()];

I just love how simple it is. I feel like I’m calling a function, but I’m not.


What else am I doing?

StackOverflow Facebook Twitter LinkedIn Live

Twitter

Pages

February 2009
M T W T F S S
« Nov   Mar »
 1
2345678
9101112131415
16171819202122
232425262728