Dynamic Content Using Html Templates

About 2-3 years ago, I was working on this project where I was receiving JSON data from the server then injecting the results into dynamically created content using the built-in JavaScript DOM methods.  It worked alright, but was a pane in the butt.  Lately, I came across idea using client side templates.  The concept of templates isn’t new, but I never thought to embed one in my HTML code.  What is even more cool, is that there are a few approaches to using the templates.  One such approach can be found here on Rick Strahl’s blog.  I saw this gentleman talk at 2009 DevConnections, really cool guy.  His approach is to clone some DOM segment and then update the element values where needed.  This works really well.  As I was searching I came across a second approach that knocked my socks off.  Below describes how this approach is used.  Currently I’m using the ASP.NET MVC pattern with my web pages but this could be done with WebForms, though there might be challenges with client IDs.  There are some helper methods from ASP.NET MCV within the html below, but they should be self explanatory.

Basics steps:

  1. Embed some hidden DOM inside a <script type=”text/html”> tags inside your page document.
  2. Make a JSON request or build an object which will be used as a data source.
  3. Using jQuery and this templating extension, you can inject the data from step 2 into the template.
  4. Insert this data injected template somewhere in your page.

So those are the basic steps, lets see some code.  I’m going to be using a html table as an example because that lends itself to the obvious add a row concept.

1. The html page with embedded template html snippet

<html>

<table id="OrderTable" width="100%" cellpadding="0" cellspacing="0">
<thead>
<tr>
<th />
<th>Quantity</th>
<th>Name</th>
<th>Price</th>
<th />
</tr>
</thead>
<tbody>
<tr>
<td><a href="”/Order/abc1234/Edit/1”">Edit</a></td>
<td> 1 </td>
<td>Some Product</td>
<td>5.50</td>
<td />
</tr>
</tbody>
</table>

<script id="RowTemplate" type="text/html"> 1:
<tr id="${Tag}_Order">
<td><a href="<%= Url.Action("Edit")%>/${Tag}">Edit</a></td>
<td>${Quantity}</td>
<td>${Name}</td>
<td>${Price} </td>
<td><a id="${Tag}_Delete" href="<%= Url.Action("Delete")%>/${Tag}">Delete</a></td>
</tr>

<div id="AddProduct">
<% using (Html.BeginForm("AddProduct", "Orders", FormMethod.Post))
{ %>
<div><input type="submit" value="Add Product" /></div>
<label>Product:</label><%= Html.DropDownList("products")%>
<label>Quantity:</label><input id="Quantity" name="Quantity" type="text" />
<% } %>
</div>

<script type="text/javascript">
$("#AddProduct form").submit(addProduct); // hijax product add form submission using jQuery

</html>
The key part of this html code is the template that is sitting inside the <script> block.  Notice there are some funny ${…} looking items in there.  This will be what our data is bound to, or in other words substituted for.  One thing I’m not diving into too much detail here, is that the events I wired up to the A links have been done in a “hijaxing” manor using jQuery
2.  Make a JSON request in order to get back some data in the form
Since our example form submission will be handled by client side JavaScript, lets look at a simple call.  Below shows the request using jQuery library which will get back a json object.   On successful call, we call the method “addProduct_succss” which will take care of our template data binding.

3 & 4.  Using the jQuery template extension inject the data and append to DOM


function addProduct_sucess(response)
{
// using template libarary, create template object using html snippet
var t = $.template($("#RowTemplate").html());
// response = { Tag:3, Quantity:2, Name:"Snuggy", Price:19.95 }, notice that property names match to template ${...} names.
var row = $(t.apply(response));
// appned this DOM row object to our table
$("#OrderTable tbody").append(row);
}
The jQuery template library will use the html snippet from the <script> block to create a template object.  Then the JSON that was returned will be applied to the template.  The key to remember here is that the JSON’s object properties, such as Quantity or Price, match to names in the template like ${Quantity} or ${Price}, respectively.

Mocking Extension Method IsAjaxRequest

I’m not 100%, but I would say mocking frameworks cannot mock extensions, this may not be true for Typemock.  Currently I’m using Moq which seems to be one of the best free mocking frameworks for unit testing in the .NET community.  I’ve been very excited of the arrival of the MVC framework from the ASP.NET community because it brings a level a development which is geared more towards test driven design.  One to the challenges with test driven design is the mocking of processes that are not relative to the code logic under test.  One such case this pops up is if you’re using the IsAjaxRequest helper method in the ASP.NET MVC.  If you’re testing your controller method and you try to mock this helper you’ll get an error “Invalid expectation on a non-overridable member”.  I don’t know if this the best advice for all types of extension methods but in this case the behavior of the IsAjaxRequest is pretty simple.  So if you’re using Moq you would have something like this:

_mockContext.Request.Setup(m => m["X-Requested-With"]).Returns("XMLHttpRequest");

Here the the IsAjaxRequest is checking a header to verify a ajax request.  The _mockContext is a mocked context object.  You can find the code for mocking the context objects here.  This code uses the Moq framework but you be substituted for another framework if desired.

JavaScript In Visual Studio 2008

If you’ve been working with web applications for some time, you’ve probably done some JavaScript coding at some point.  For a long time it was difficult to do two things well: 1) code with consistency in JavaScript and 2)  write code neatly with good formatting. 

On the first issue, I’ve praised the release of such wonderful JavaScript frameworks such as jQuery, Prototype.js, and others.  With Visual Studio 2008 you can get intelliscence with your JavaScript whether you are writing it in the DOM or in a separate .js file.  This is huge!  Now you don’t have to go searching through the docs just to find the name of the method you’re trying to call.  One thing I was stuck with for a while is how to get intelliscence in a separate .js file.  You can do this in the following two ways:

  • Type the following line at the top of your .js file: “/// <reference path="../jquery-1.3.2.min-vsdoc.js" />” (note that this is the VS doc for jQuery which ships with ASP.NET MVC or downloaded from jQuery Docs.  It will be included in box with VS2010)

OR

  • Open you solution in visual studio.  Open you .js file that uses some other framework.  Using the mouse, drag the .js framework file (such as Prototype.js) onto your .js file.  This will automatically add the <reference> node to the .js file.

Visual Studio has also helped a lot with auto-formatting (use Ctrl+K+D to perform initiate the auto format for a page).  Now your JavaScript code can look clean and readable just like your C# code.  There is one difference though, between the C# formatting and the JavaScript formatting, the placement of the {} brackets.  Some people like the opening { on the same line as the method/function declaration.  C# formatting by default puts the { } on they’re own line, which I’ve come to like.  If you’re like me, I like things to be consistent.  The following steps show how to change the placement of the { so that it behaves like the C# style.

  1. Go to Tool^Options menu.
  2. Navigate to the Text Editor node, then to the JScript node, then to the Formatting node.
  3. On the Formatting node click the check box that says “Place open brace on new line for functions”.

Using Database Project Cross-Database References

Visual studio an excellent project template for database management; currently it supports project templates for 2000, 2005, and 2008 SQL Server.  Depending on the version of Visual Studio you are using, you may need to install the latest for 2008 templates here.  In this post I will describe a scenario where you might be using linkservers to reference a database that you possibly aren’t managing or do not want to add to the database solution you are working on.  Below describes the scenario I came up against and used the cross-database reference to solve it.

Scenario:  You have a database solution with various database projects.  In one of these database projects, you have some code, say in a stored procedure, that has a line “SELECT … FROM MyRemoteServer.MyRemoteDb.dbo.TableAbc A …”.  When you go to build your database project, it fails and says “… has an unresolved reference to object …”.  So, we needed a way to have a reference to this report database schema without creating a project within our solution.

Fix: A way to fix this scenario is to use a cross-database references.  This msdn article outlines some of the reasons you might want to do this http://msdn.microsoft.com/en-us/library/bb386242%28VS.80%29.aspx.  In our case we didn’t want to create a project for this remote database schema that didn’t change.  So in order to fix the references that cause the build errors we had to import the remote database into a .dbschema file using the VSDBCMD tool.  This can be found here http://msdn.microsoft.com/en-us/library/dd172135.aspx.  Once the .dbschema file is create you can add it to you solution.  Once it’s in the solution, you can go to your project, right click References and do a “Add Database Reference…”.  Choose “Database project schema” for which you will browse to the .dbschema file that was just added to solution.  Once you have added the reference, go to the project properties and view the references (see picture below).  You will need to associate a server and database variable name for this reference.  Now that you have these variables the problematic build code described in the Scenario will need to be changed to this “SELECT … FROM [$(ServerVarName)].[$(DatabaseVarName)].dbo.TableAbc A …”.  With this in place the build will succeed because the project can now resolve the remote database objects through the addition of the .dbschema file.

proj_refs