Practical ASP.NET

Setting Up for jQuery Templates

Peter Vogel prepares to try out the new jQuery templating/databinding functionality to create a simple AJAX-enabled page that allows the user to select a customer and retrieve from a Web service all the orders associated with that customer.

Starting with my next column, I'm going to focus on the new databinding and templating features that Microsoft has contributed to the jQuery project. In this column I'm going to build the base project that I'll be integrating the new jQuery features into.

I have three goals in this project:

  • Offload as much processing as possible to the client
  • Have the client talk to the server exclusively through JavaScript calling WCF Web services
  • Leverage as much ASP.NET technology as possible

The page I'm going to create is very simple: The user will get a list of customers from which to select (that list will be loaded on the server). Once the user selects a customer, a list of existing orders for that customer will be displayed. The user will then be able to update and delete orders. While I could implement adding new orders (as I did in earlier projects) it wouldn't leverage the jQuery extensions, so I'm going to skip that.

As my first steps, I set up an ASP.NET application, copy the Northwind database into the application's App_Data folder, and create an Entity Framework model based on the Northwind database containing Customer, Order, OrderDetail and Product entities.

I also define a Data Transfer Object, for moving data between the client and server. The following code shows one of the properties on the DTO, RequiredDate, which I move between the client and the server as a string (the JSON format for transferring data in AJAX doesn't understand the concept of "DateTime" and, while WCF has a hack for dealing with dates, it's easier just to convert my dates to strings). The KnownType attribute ensures that code in my project can serialize and deserialize my DTO:

<System.Runtime.Serialization.KnownType(GetType(dtoOrder))> _
Public Class dtoOrder

    Private _RequiredDate As String
    Public Property RequiredDate() As String
        Get
            Return _RequiredDate
        End Get
        Set(ByVal value As String)
            _RequiredDate = value
        End Set
    End Property
...  more properties... 

With my business layer created, I add my Northwind data factory: an AJAX-enabled WCF service called NorthwindData. The first method I add to the service uses LINQ to return a list of my DTOs (one for each order for the customer id passed to the method) with a re-formatted date:

<ServiceContract(Namespace:="PHVIS")> _
<AspNetCompatibilityRequirements(
  RequirementsMode:=AspNetCompatibilityRequirementsMode.Allowed)> _
Public Class NorthwindData

<OperationContract()> _
Public Function GetOrdersForCustomer(ByVal CustId As String) _
As List(Of dtoOrder)
Dim nw As New northwndEntities
Dim res As New List(Of dtoOrder)
Dim dto As dtoOrder

  Dim ords = From o As Orders In nw.Orders.Include("Customers") _
           Where (o.Customers.CustomerID = CustId) _
           Select o

  For Each o As Orders In ords
    dto = New dtoOrder With {
     .CustomerId = o.Customers.CustomerID, _
     .CompanyName = o.Customers.CompanyName, _
     .RequiredDate = Format(o.RequiredDate, "MM/dd/yyyy"), _
     .OrderId = o.OrderID}
     res.Add(dto)
  Next

  Return res
End Function
End Class

Turning to my ASP.NET. page, I add a dropdownlist called lstCustomers to display the list of customers and tie it to an EntityDataSource. That EntityDataSource retrieves all the Customer entities from my EF model, displaying just the CompanyName but holding the CustomerId in the list's data property. I also add a "Select Customer" item to the top of the list.

While I created and configured these components in Design view, here's what the results look like in Source view:

<asp:DropDownList ID="lstCustomers" runat="server" 
            DataSourceID="CustomerDataSource"
      DataTextField="CompanyName" 
            DataValueField="CustomerID" 
Height="24px" Width="193px" 
            AppendDataBoundItems="True">
            <asp:ListItem>Select Customer</asp:ListItem>
</asp:DropDownList>

<asp:EntityDataSource ID="CustomerDataSource" runat="server" 
            ConnectionString="name=northwndEntities" 
            DefaultContainerName="northwndEntities"
EntitySetName="Customers" 
            Select="it.[CompanyName], it.[CustomerID]">
</asp:EntityDataSource>

I drag a ScriptManager on to the page and add a reference to my Web service to its Services collection. Rather than host the jQuery files in my application, I also add, to the ScriptManager's Scripts collection, references to the jQuery core library and the new templating extension library in Microsoft's Content Delivery Network. Finally, I add a reference to the script library containing the scripts for my page.

Again, I made all of these changes in Design view and in the ScriptManager's Properties list, but the result looks like this in source view:

<asp:scriptmanager runat="server" ID="Scriptmanager1">
  <Scripts>
    <asp:ScriptReference Path=
      "http://ajax.microsoft.com/ajax/jquery/jquery-1.4.4.min.js" />
    <asp:ScriptReference Path= 
      "http://ajax.microsoft.com/ajax/jquery.templates/beta1/
                     jquery.tmpl.min.js" />
    <asp:ScriptReference Path="~/Scripts/DisplayOrders.js" />
  </Scripts>
  <Services>
    <asp:ServiceReference Path="~/NorthwindData.svc" />
  </Services>
</asp:scriptmanager>

And now, it's time to add some JavaScript. Once the page is loaded, I want to run a JavaScript function I've called InitializePage, where I link events fired by HTML elements on my page to my JavaScript functions. Using jQuery that code looks like this:

$(InitializePae);

At this point in the project, the only event I want to wire up is the dropdownlist's change event. The jQuery code to attach a JavaScript function called GetOrders to the lstCustomers' change event looks like this:

function InitializePage() {
    $("#lstCustomers").change(GetOrders);
}

I'm ready now to call my Web service in my GetOrders function. That function will retrieve the current value from lstCustomers and pass that to the GetOrdersForCustomer method in my Web service. When the results come back, I'll call another function named GotOrders that will catch the service's results (if anything goes wrong, I'll call a function named FailOrders that catch the error). Thanks to the ScriptManager, that code looks like this:

function GetOrders() {
    var custId = $("#lstCustomers").val();
    var nwData = new PHVIS.NorthwindData();
    nwData.GetOrdersForCustomer(custId, GotOrders, FailOrders);
}

function GotOrders(ords) {
    alert(ords.length);
}

function FailOrders(res) {
    alert(res._message);
}

And, in my next column, I'll use the new templating functions to display those objects.

About the Author

Peter Vogel is a system architect and principal in PH&V Information Services. PH&V provides full-stack consulting from UX design through object modeling to database design. Peter tweets about his VSM columns with the hashtag #vogelarticles. His blog posts on user experience design can be found at http://blog.learningtree.com/tag/ui/.

comments powered by Disqus

Featured

  • Hands On: New VS Code Insiders Build Creates Web Page from Image in Seconds

    New Vision support with GitHub Copilot in the latest Visual Studio Code Insiders build takes a user-supplied mockup image and creates a web page from it in seconds, handling all the HTML and CSS.

  • Naive Bayes Regression Using C#

    Dr. James McCaffrey from Microsoft Research presents a complete end-to-end demonstration of the naive Bayes regression technique, where the goal is to predict a single numeric value. Compared to other machine learning regression techniques, naive Bayes regression is usually less accurate, but is simple, easy to implement and customize, works on both large and small datasets, is highly interpretable, and doesn't require tuning any hyperparameters.

  • VS Code Copilot Previews New GPT-4o AI Code Completion Model

    The 4o upgrade includes additional training on more than 275,000 high-quality public repositories in over 30 popular programming languages, said Microsoft-owned GitHub, which created the original "AI pair programmer" years ago.

  • Microsoft's Rust Embrace Continues with Azure SDK Beta

    "Rust's strong type system and ownership model help prevent common programming errors such as null pointer dereferencing and buffer overflows, leading to more secure and stable code."

  • Xcode IDE from Microsoft Archrival Apple Gets Copilot AI

    Just after expanding the reach of its Copilot AI coding assistant to the open-source Eclipse IDE, Microsoft showcased how it's going even further, providing details about a preview version for the Xcode IDE from archrival Apple.

Subscribe on YouTube

Upcoming Training Events