After my previous article, where I showed you how to use user controls as views, in this post I will show you how to mix in some jQuery templating.
The jQuery templates plugin is basically a way to make views in JavaScript, much like we did with the user control. You can get the plugin here: http://ajax.aspnetcdn.com/ajax/jquery.templates/beta1/jquery.tmpl.min.js
jQuery templates: the basics
Let me first show a quick example of how jQuery templates work.
First of all you need to create a template. Templates should be placed inside a script-tag with the type set to text/html or text/x-jquery-tmpl (the latter is the official version, but it doesn’t validate on HTML 5, after a little bit of fiddling I noticed text/html also works and validates nicely). The reason you don’t put text/javascript is because then the browser will try to execute it.
So let’s see a small sample for this:
<div id="result"> </div> <script type="text/html" id="tmplPerson"> ${FirstName} ${LastName} </script>
This is basically the same template we used in the user control, but it’s now a client-side template. We can feed JSON objects into this template and add the resulting markup to an existing element (result-div):
var p = { FirstName: "Kenneth", LastName: "Truyers" } $("#tmplPerson").tmpl(p).appendTo($("#result"));
This code-snippet:
- Looks for the template
- Applies the object p to it
- Adds the result to our div
In this case I only applied one object to the template, but the jQuery templating engine is smart enough to know that when you pass in an array it has to render one template for each object.
Templating data retrieved by AJAX
In my post on how to connect jQuery and ASP.NET web services we saw that you can get these types of objects from a web service. So now let’s get these object from a web service and apply those to the template:
$(document).ready(function () { $("#btnMore").click(onBtnMoreClicked); }); function onBtnMoreClicked() { $.callAsmx("GetPersons", {}, onLoaded); } function onLoaded(persons) { $("#tmplPerson").tmpl(persons).appendTo($("#result")); }
When a button gets clicked, a web service is called to get the list of persons. When the data returns we do exactly the same thing as in the first example, but now with a list of objects. The result is that for each item in the list, the template will be added to my result div.
Taking it one step further
So now we have two ways of templating our data: one on the client-side through jQuery templates, and one on the server-side through user controls and repeaters. Wouldn’t it be nice to have those two come together? After all, if I change the view of a person I don’t want to have to change it in two places (DRY).
Well, I found a little trick for that. If we compare the user control and the jQuery template, we see that the only difference is either the direct assignment or the jQuery template syntax. In the code-behind of the user control I added this little function:
Public Function GetVal(PropertyValue As String) As String If Me.Person Is Nothing Then Return "${" & PropertyValue & "}" Else Return DataBinder.Eval(Person, PropertyValue) End If End Function
What this function does is quite easy:
- If we have an instance of Person, it will output the value of the requested property.
- If there’s no instance, it outputs the jQuery placeholder string.
Let’s update the user control so that, instead of taking the value directly from the Person-object, it calls this function:
<%@ Control Language="VB" AutoEventWireup="false" CodeFile="personview.ascx.vb" Inherits="personview" %> <span><%= GetVal("LastName")%></span> <span><%= GetVal("FirstName")%></span> <br />
Now, with this in place, let’s use the user control in the repeater, just as we did before. This will render the complete list of persons that we assign to it on the server.
Aside from that we’ll also add this user control on the bottom of the page, without a person attached, within the scripttemplate-tag. This will then create the same output, only with jQuery template placeholders. Here you can see the complete markup of the page:
<div id="result"> <asp:Repeater ID="repPeople" runat="server"> <ItemTemplate> <view:person ID="per" runat="server" Person='<%# Container.DataItem %>' /> </ItemTemplate> </asp:Repeater> </div> <input type="button" id="btnMore" value="Get More!" /> <script type="text/html" id="tmplPerson"> <view:person ID="jquerytemplate" runat="server" /> </script>
This is the resulting HTML-output:
<div id="result"> <span>Truyers</span> <span>Kenneth</span> <br /> <span>Doe</span> <span>John</span> <br /> </div> <input type="button" id="btnMore" value="Get More!" /> <script type="text/html" id="tmplPerson"> ${LastName} ${FirstName}
</script>
You can see that the first two items were created on the server and sent immediately as HTML. The user control we added to our script-tag however, has not rendered data but instead rendered our jQuery template.
Now each time we press the button, we will retrieve more items from the server and add them to the results-div.
The big advantage here is of course that if you update your user control, the jQuery template will be updated accordingly and you don’t have to touch your client-side part, it will automagically grow with the user control.
You can see this in action by downloading the attached ZIP-file: