Jul 1
2009 Goals - July Update
icon1 Darrell Mozingo | icon2 Goals | icon4 July 1st, 2009| icon32 Comments »

We’re half way through 2009. How am I doing on my goals for the year? Let’s see (comments in italics after each goal):

Books

  1. Code Complete - Steve McConnell (yep, I’ve never actually read it)    No progress.
  2. Patterns of Enterprise Application Architecture - Martin Fowler    Ordered and on my bookshelf.
  3. Domain Driven Design - Erick Evans    A bit over 100 pages left.
  4. Working Effectively With Legacy Code - Robert Martin    No progress.

Tools/Techniques/Processes @ Work

  • NHibernate and all its trimmings (FluentNHibernate, LINQ to NHibernate, etc), which I’ll need on a project here real soon.  Done, but still picking up stuff.
  • Actually move from CC.NET to Team City (last attempt didn’t go so well).  No progress.
  • Build a more robust build script and management process - including production deployment scenarios.   No progress.
  • Messaging framework, either MassTransit, NServiceBus, or Ayende’s new Rhino Service Bus if he’s able to release it in time for our current project.  No progress as we haven’t needed any yet.

Involvement

  • We have weekly meetings to catch everyone up on what we’re doing, but I want to present on an actual topic during at least 2 of these - and present in a way where the other development teams will see the use in picking up the presented tool/technique.    Our meetings are still halted, but I’m hoping to do an intro IoC/DI presentation if they ever start again.
  • Have at least one meeting of the CantonALT.NET group and see if it can ever get up on its feet.   No progress, but we have had a few Code & Coffee get togethers.
  • The two blog posts per month target John put out there seems doable, so I’ll borrow it :)    Pretty much on target.
  • At least 3 feature/patch submissions to open source projects.  No further progress past the last update.

Productivity

  • Trim RSS feed size by 1/3 (presently at 127, so trim it to at least 85) and cut time viewing it by half. I’ve gotten much better this past year at cutting through the useless stuff, but there’s still a lot there and it sucks up too much of my time.  Down to 103. Not too bad.

Once again, the reading is killing me. It’s not that it’s not interesting, it’s just time. Between a few magazines I read (some technical, some not) and projects around the house, reading time always seems to take a back seat. I’ll get into it for a bit and fly through the pages, but that “bit” is usually only a day or two, unfortunately. Lets see how the next two months go.

I’ll update again in the begining of September.

Jun 20

Part 1 discussed the benefits of a strongly typed view and part 2 went through the typical usage of the Mvc Contrib project’s fluent HTML library. Now we’ll take a look at a neater usage for it - validation.

Each extension in the Mvc Contrib fluent HTML library takes “behaviors” into account, applying all known behaviors first when rendering themselves to strings. These behaviors are defined by the following interface:

1
2
3
4
public interface IMemberBehavior : IBehaviorMarker
{
	void Execute(IMemberElement element);
}

Very simple. The interface defines a single method that takes in an IMemberElement, which provides the LINQ expression being used to render the control and also inherits from the IElement interface, which is the base interface all the HTML extensions end up deriving from:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public interface IElement
{
	/// <summary>
	/// TagBuilder object used to generate HTML.
	/// </summary>
	TagBuilder Builder { get; }
 
	/// <summary>
	/// How the tag should be closed.
	/// </summary>
	TagRenderMode TagRenderMode { get; }
 
	/// <summary>
	/// Set the value of the specified attribute.
	/// </summary>
	/// <param name="name">The name of the attribute.</param>
	/// <param name="value">The value of the attribute.</param>
	void SetAttr(string name, object value);
 
	/// <summary>
	/// Set the value of the specified attribute.
	/// </summary>
	/// <param name="name">The name of the attribute.</param>
	string GetAttr(string name);
 
	/// <summary>
	/// Remove an attribute.
	/// </summary>
	/// <param name="name">The name of the attribute to remove.</param>
	void RemoveAttr(string name);
 
	/// <summary>
	/// The text for the label rendered before the element.
	/// </summary>
	string LabelBeforeText { get; set; }
 
	/// <summary>
	/// The text for the label rendered after the element.
	/// </summary>
	string LabelAfterText { get; set; }
 
	/// <summary>
	/// The class for labels rendered before or after the element.
	/// </summary>
	string LabelClass { get; set; }
}

This allows a behavior to do basic modifications to an element, including changing HTML attributes and adding text before/after the element. More advanced operations can be done by breaking polymorphism and checking what type the IElement parameter actually is. Mvc Contrib bundles in one behavior by default, the ValidationBehavior, which checks ASP.NET MVC’s ModelState for any possible errors to display, effectively making the Mvc Contrib’s HTML helpers act the same as the built in ASP.NET MVC’s when it comes to error handling.

You’ll notice above I said each HTML extension takes all “known” behaviors into account when rendering themselves to strings. So how do the extensions learn about these behaviors? Simply put, the ModelViewPage we had our view page inherit from takes an array of them in one of its constructor overloads. The default constructor only loads the ValidationBehavior. All we need to do is create our own view base page, inherit from the ModelViewPage, and pass in our own behaviors like so:

1
2
3
4
5
6
7
public class FluentViewPage<T> : ModelViewPage<T> where T : class
{
	public FluentViewPage()
		: base(new MaxLengthBehavior())
	{
	}
}

There’s really not much to the above behavior, either. Simply have it inherit from IMemberBehavior and you’re good to go. Here it is in all its entirety:

1
2
3
4
5
6
7
8
9
10
11
12
public class MaxLengthBehavior : IMemberBehavior
{
	public void Execute(IMemberElement element)
	{
		var attribute = new MemberBehaviorHelper<StringLengthAttribute>().GetAttribute(element);
 
		if(attribute != null && element is ISupportsMaxLength)
		{
			element.SetAttr(HtmlAttribute.MaxLength, attribute.MaximumLength);
		}
	}
}

The passed in member element knows the property specified in the this.TextBox(x => x.Name) call (Name, in this case), as well as all the elements defined on the IElement interface above. We take that and use a helper class to pull the desired attribute off the passed in property. If it has the attribute we’re looking for, and supports setting a maximum length (checking using the ISupportsMaxLength marker interface so we’re not trying to somehow set the max length on a checkbox, for example), we set the max length HTML attribute on the element. Pretty simple, but again, this is only really scratching the surface of what can be done with these behaviors.

So with all this in place, simply slap the StringLenght attribute on any needed view model properties. For instance, if we modify the CustomerViewModel’s name property like this:

1
2
[StringLength(30)]
public string Name { get; set; }

The outputted HTML would be:

1
<input id="Name" maxlength="30" name="Name" type="text" value="John" />

Neat, huh? In our current project, we’re using these to automatically denote required fields, and in conjunction with xVal, require those fields complete with client side checks. All from a few simple attributes.

A zip of the final project can be found here, for reference.

Jun 17
TortoiseSVN 1.6+ Hot Keys
icon1 Darrell Mozingo | icon2 Quickie | icon4 June 17th, 2009| icon3No Comments »

The latest releases of Tortoise SVN (above 1.6) have taken away the ALT+O hot keys that used to be on every dialog (though it sounds like they’ve added them back in to the trunk). This caused quite an uproar by many keyboarders, myself included.

Until the trunk is stable and the ALT+O keys are reintroduced, though, know that CTRL+ENTER will substitute on pretty much all the dialogs (or ESC for Cancel). These are the “standard” Windows OK & Cancel shortcuts, and apparently the custom accelerator keys are hold overs from legacy WinAPI code.

I’ve grown accustomed to CTRL+ENTER at this point, but I’ll be happy to hopefully have my old friend, ALT+O, back soon.

Jun 10
Code & Coffee - Getting Started
icon1 Darrell Mozingo | icon2 Events | icon4 June 10th, 2009| icon3No Comments »

We had a couple of new guys join us for last week’s Code & Coffee, and during the 15 minutes or so we spent helping get them up to speed I realized a quick “getting started” post might be in order to help future attendees.

For starters, download the Ruby 1.8.6 one-click installer (from the main Ruby site). It may or may not require a reboot to get the standard C:\ruby install directory into your PATH variable. Open a command prompt and type ruby --version to make sure it’s working correctly.

We’re working our way through Edge Case’s Ruby Koans right now, which are basically a whole suite of failing unit tests that teach you more about the language as you get them passing. There’s a download link in the middle of the upper portion of their GitHub page. Once you download and extract it somewhere, open up a command prompt in the root directory and run the rake command. It will use the Rakefile in that directory by default and it should tell you the first test failed. Open the respective file in the koans directory, try getting it to pass, and re-run rake. Keep going through that process, test by test. Some are blatantly obvious, while others require some research. It’s best if you think about what you’re actually doing too, besides just trying to make the test pass. We’re currently somewhere in the about_hashes.rb file.

The idea is to get through these, soaking up as much as we can, then probably jump into an intro Rails application, eventually working on some sort of blog for the Code & Coffee. Should be fun. I’d also like to get into either RSpec or Cucumber along the way, and see what TDD/BDD in Ruby is like as I’ve always heard how great it is.

Our next get together will be Friday, June 19th @ 7am. Hope to see you there, and let me know if you have any problems with getting this stuff setup.

May 24
Code and Coffee - Inital Impressions
icon1 Darrell Mozingo | icon2 Events | icon4 May 24th, 2009| icon3No Comments »

We’ve had two meet-ups for the Code and Coffee already now, and it seems to be going pretty good. We decided to tackle a simple Rails application, as none of us had used Ruby or Rails before much, and thought it’d be worth taking a look at it.

We’re working through EdgeCase’s Ruby Koans to familurize ourselves with Ruby first, then we’ll start tackling some Rails examples. The Koans are a great way to introduce people to the language. Really, they’re brilliant. The meet-ups have stuck to about an hour in length so far, and we’ve determined we’ll meet every other Friday, still as 7am at the Canton Arabica that was previously mentioned. That puts our next get together on June 5th.

It was only Jason Lautzenheiser, Eric Schliffka, and myself there, but we’re hopeful more people will start coming. There’s been quite a bit of interest, so we’ll see. Looks like these meetings will be pretty helpful, though, keeping all of us on tasks, meeting some new people, and most important, pushing our comfort zone in development terms. They’re pretty fun, to boot! Hope to see you at the next one!

May 23

In part 1, I explained the reasoning behind using strongly typed HTML helpers in your view (with ease of refactoring being chief among them). Now that you have an ASP.NET MVC project referencing the needed Mvc Contrib assemblies, how can you actually get started using them?

Lets start by taking this sexy looking view model that represents a single customer:

1
2
3
4
5
6
public class CustomerViewModel
{
	public int Id { get; set; }
	public string Name { get; set; }
	public CustomerType Type { get; set; }
}

Where CustomerType is a standard enumeration:

1
2
3
4
5
6
public enum CustomerType
{
	Preferred,
	Standard,
	Delinquent
}

Then we’ll provide an easy enough action for editing a customer:

1
2
3
4
5
6
7
8
9
10
11
12
// In reality, we'd take in a customer Id and use that to load the customer from the database.
public ActionResult Edit()
{
	var customerViewModelLoadedFromDatabase = new CustomerViewModel
	                                          	{
	                                          		Id = 10,
	                                          		Name = "John",
                                                    		Type = CustomerType.Standard
	                                          	};
 
	return View("Edit", customerViewModelLoadedFromDatabase);
}

Before looking at the view, though, we’ll need to reference the MvcContrib.FluentHtml.dll assembly, and add the following to our web.config, under the configuration/system.web/pages/namespaces node:

1
<add namespace="MvcContrib.FluentHtml" />

With all that out of the way, here’s the relevant portion of the edit view:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<% using(Html.BeginForm<CustomerController>(x => x.Update(null))) { %>
	<%= this.Hidden(x => x.Id) %>
 
	<table>
		<tr>
			<td><b><%= this.Label(x => x.Name) %>:</b</td>
			<td><%= this.TextBox(x => x.Name) %></td>
		</tr>
		<tr>
			<td><b><%= this.Label(x => x.Type).Value("Customer Type") %>:</b></td>
			<td><%= this.Select(x => x.Type).Options<CustomerType>().Selected(Model.Type) %></td>
		</tr>
		<tr>
			<td colspan="2" align="center">
				<%= this.SubmitButton("Update Customer") %>
			</td>
		</tr>
	</table>
<% } %>

First, note that the page must inherit from MvcContrib.FluentHtml.ModelViewPage, not the standard Mvc ViewPage class. The strongly typed Html.BeginForm is from the Mvc Futures Assembly. Also, these extensions are on the ModelViewPage base class, not the normal Html helper type methods (i.e. they’re this.TextBox instead of Html.TextBox).

These fields are mostly self explanatory: you’ll see the Id is written to a hidden field on the page using the Hidden extension, the Name using the TextBox extension, and the Type (as a drop down list) using the Select extension. All of these extensions have quite a few customizable methods on them, such as the Options and Selected methods on the Select extension shown above. The options method allows you to specify (via generic type or otherwise with an overload) the options for the drop down, while the selected method allows you to specify which option of the list should be highlighted (it’ll default to the top item if the parameter is null). The Label extension can generate an HTML label “for” the specified control, so by clicking the “Name” or “Customer Type” labels above, most browsers will set focus to their respective controls.

Another quite useful extension is the this.IdFor(x => x.Name), which for our setup would simply output Name, but it comes in handy when dealing with sub objections and collections. This allows you to put a strongly typed reference to your control id’s in Javascript, so renaming the view model’s property renames all references, including the Javascript ones. Huge help there.

Alright, I’ll admit for basic cases like this it’s a bit harder to see the immediate benefits of strong typing, so let’s complicate it a tad by introducing a sub view model for an address, and a collection of order view models by adding this in the Edit action to the customer object initialization:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Address = new AddressViewModel
          	{
          		Street = "123 Easy St.",
          		City = "Beverly Hills",
          		State = "CA",
          		Zip = "90210"
          	},
Orders = new List<OrderViewModel>
         	{
         		new OrderViewModel
         			{
					Id = 300,
         				ApplyDiscount = true,
         				Quantity = 10
         			},
         		new OrderViewModel
         			{
					Id = 301,
         				ApplyDiscount = false,
         				Quantity = 20
         			}
         	}

Here’s one way to modify the edit page to deal with these new objects:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<tr>
	<td><b>Address:</b></td>
	<td>
		<table>
			<tr>
				<td>Street:</td>
				<td><%= this.TextBox(x => x.Address.Street) %></td>
			</tr>
			<tr>
				<td>City:</td>
				<td><%= this.TextBox(x => x.Address.City) %></td>
			</tr>
			<tr>
				<td>State:</td>
				<td><%= this.TextBox(x => x.Address.State).Styles(width => "30px") %></td>
			</tr>
			<tr>
				<td>Zip:</td>
				<td><%= this.TextBox(x => x.Address.Zip) %></td>
			</tr>
		</table>
	</td>
</tr>
<tr>
	<td><b>Orders:</b></td>
	<% for(int i = 0; i < Model.Orders.Count; i++) { %>
		<td>
			<%= this.Hidden(x => x.Orders[i].Id) %>
			<table>
				<tr>
					<td>Quantity:</td>
					<td><%= this.TextBox(x => x.Orders[i].Quantity) %></td>
				</tr>
				<tr>
					<td><%= this.Label(x => x.Orders[i].ApplyDiscount).Value("Apply Discount") %>:</td>
					<td><%= this.CheckBox(x => x.Orders[i].ApplyDiscount)%></td>
				</tr>
			</table>
		</td>
	<% } %>
</tr>

You’ll notice this is all still in a strongly typed manor, even with the sub object and object collection. These are basically the same extensions as before, except for CheckBox, which works as you’d expect. Note the Styles method on most of these extensions, which takes a param of Func’s that allows you to define CSS styles. The state text box, for examples, is defining the width CSS style and setting it to 30px.

All of these extensions take the current ViewData into account when rendering, just as the default ASP.NET MVC extensions do. For instance, the above CheckBox extension will render “checked” if the ApplyDiscount property is true coming in. You can also start to imagine how using the this.IdFor(x => x.property) extension to reference controls in your Javascript would start to come in handy here, as HTML id tag rendering for arrays (where the brackets are replaced with underscores) and sub objects (where dots are replaced with underscores) can get pretty complex.

That pretty much covers the basics of the FluentHTML extensions. These reasons alone were enough to get my team to switch our current project over to using them, let alone some of the more advanced features, such as basic validation integration. I’ll go over a few of those in the next part of this series, though. You can grab a zip of the current project here.

May 8
Code and Coffee
icon1 Darrell Mozingo | icon2 Events | icon4 May 8th, 2009| icon32 Comments »
Coffee and Code

A week or two ago Jason Lautzenheiser emailed around about to a few of us about starting a local Code and Coffee here in the Canton area, and I think it’s a great idea. We haven’t set a schedule or anything, but the first get together will be Friday, May 15th @ 7 AM at Canton Arabica, right on Dressler in Belden. Everyone’s already busy in the evenings, so we figure we’ll give this whole “first thing in the morning” time slot a shot.

Basically we’ll get together to do some pairing on whatever interests everyone, with an eye towards pushing comfort zones (read: new languages and technologies). Very informal. Stop by if you can make it. If we can’t figure out what we’ll do before next Friday, we’ll just call this first one a meet and greet and pick a topic for next time. Since the idea is to pair, don’t worry if you don’t have a laptop.

Don’t fret about the early AM thing. I’m not a morning person myself either (my alarm isn’t even set until 7:20 normally), but it should be good to get the ol’ brain neurons firing that early in the morning.

If you’re interested, let either Jason or myself know. We’re planning on keeping it to about an hour in length.

Hope to see you there!

May 1
2009 Goals - May Update
icon1 Darrell Mozingo | icon2 Goals | icon4 May 1st, 2009| icon3No Comments »

We’re 1/3rd of the way through 2009. How am I doing on my goals for the year? Let’s see (comments in italics after each goal):

Books

  1. Code Complete - Steve McConnell (yep, I’ve never actually read it)    No progress.
  2. Patterns of Enterprise Application Architecture - Martin Fowler    Ordered and on my bookshelf.
  3. Domain Driven Design - Erick Evans    About half way through - good stuff!
  4. Working Effectively With Legacy Code - Robert Martin    No progress.

Tools/Techniques/Processes @ Work

  • NHibernate and all its trimmings (FluentNHibernate, LINQ to NHibernate, etc), which I’ll need on a project here real soon.  Done (though with NHibernate, learning is always ongoing!)
  • Actually move from CC.NET to Team City (last attempt didn’t go so well).  No progress.
  • Build a more robust build script and management process - including production deployment scenarios.   Worked on the script and have a very basic one up and running. The build portion needs a lot more refinement before I get anything more advanced in there though.
  • Messaging framework, either MassTransit, NServiceBus, or Ayende’s new Rhino Service Bus if he’s able to release it in time for our current project.  No progress as we haven’t needed any yet.

Involvement

  • We have weekly meetings to catch everyone up on what we’re doing, but I want to present on an actual topic during at least 2 of these - and present in a way where the other development teams will see the use in picking up the presented tool/technique.    Our meetings were/are halted for a bit, but I think an intro IoC/DI presentation when they pick back up in a bit is in order.
  • Have at least one meeting of the CantonALT.NET group and see if it can ever get up on its feet.   No progress.
  • The two blog posts per month target John put out there seems doable, so I’ll borrow it :)    Sorta keeping on target - I didn’t really have two substantial ones in March, but I made up for it (just in time yesterday!) by doing 3 in April.
  • At least 3 feature/patch submissions to open source projects.  Submitted quite a few patches (some small, some a bit meatier) to the MVC Contrib project and one (yet unaplied) one to the xVal project. So while I guess this goal is technically met, I’d still like to do something of a little more substance to push myself.

Productivity

  • Trim RSS feed size by 1/3 (presently at 127, so trim it to at least 85) and cut time viewing it by half. I’ve gotten much better this past year at cutting through the useless stuff, but there’s still a lot there and it sucks up too much of my time.  Down a bit to 116. Hey, it’s a start!

Starting on the reading was good, but only half a book in two months is pretty sad. Everything else is more or less on schedule, but I need to start thinking about that CantonALT.NET meeting (or something similar).

I’ll update again in the begining of July.

Apr 30

Out of the box, ASP.NET MVC uses weakly typed extension methods to generate various HTML elements (inputs, check boxes, select lists, etc). By weakly typed I mean they require strings, which are actually strings based on the properties of your view model. For instance, given this view model:

1
2
3
4
5
public class OrderViewModel
{
	public int Quantity { get; set; }
	public bool ApplyDiscount { get; set; }
}

You’d generate an input box for the quantity, using the standard HTML helper extensions, like so:

1
<%= Html.TextBox("Quantity") %>

Ew, strings. That’s so .NET 1.1, right? With .NET 3 we get Expressions and lambdas. Now lambdas are just more concise ways to define delegates (methods you can pass around as variables), so they’re nothing really new new. Expressions, for the purposes of this post, allow you to specify, in a compile safe manner, which property you want to use for something, which can then be parsed during run-time to get the property’s string name (suffice to say Expressions can do much more and form the foundation for LINQ To SQL). For instance, what if, instead of using the above TextBox method for the quantity product, we could do this:

1
<%= Html.TextBox(x => x.Quantity) %>

Rest assured it’d produce the same HTML in the end while giving us the type safety we’re looking for. What do I mean by type safety? I mean you can preform a rename refactoring on Quantity and you’d also rename the usage in the view (Resharper will actually do most rename refactorings on strings too, but it’s not 100% reliable - it’s a guess at best). That means less chance of something breaking (especially something you won’t find out about until runtime when your customers are in there), which means high quality, which is just cool.

OK, so we’re aware of what a strongly typed view would look like and the benefits of it. How can we do it? Well, we can roll our own (which has been done in a few places very nicely but is quite a bit of work), we can use the basic ones provided in the MVC Futures assembly (which provide pretty much the same functionality, look, and feel as the existing ones in System.Web.Mvc but with the strong typed goodness), or we can use the ones included in the open source MVC Contrib project. This is a project that provides a lot of really nice “glue” to help out with any ASP.NET MVC project, taking advantage of many of the extensibility points built into the framework already.

Unfortunately, it looks like the latest release download doesn’t include the Fluent Html assembly (fluent html is what most people use when referring to this strong typed HTML tag output because it’s a “fluent” interface, as you’ll see shortly). You’ll need to build the project from source, so grab the latest copy at http://mvccontrib.googlecode.com/svn/trunk, then run the ClickToBuild batch file in the root folder. It’ll do it’s thing, then when it’s finished you’ll need to grab the following files in the newly created buildnet-3.5.win32-MVCContrib-release folder:

  • MvcContrib.dll
  • MvcContrib.pdb (optional - provides line numbers if you need to debug anything)
  • MvcContrib.xml (method and parameter comments)
  • MvcContrib.FluentHtml.dll
  • MvcContrib.FluentHtml.pdb
  • MvcContrib.FluentHtml.xml

In the next part I’ll go over the basic usage of the library, then in the third part I’ll cover some of the cooler aspects, like tying it into validation and other things.

Apr 30

We’re using ASP.NET MVC on my current project at work, and we’re heavily exploring jQuery and other client side tools for AJAX effects. One of the first areas where we needed it was a screen where the user enters a zip code and a list of various values get returned based on that code. We got it working just fine rather quickly, but only by slinging some nasty looking spaghetti code in the JavaScript, so we started looking around for a possible solution.

One of the first things we stumbled on was jTemplates, a client side templating plug-in for jQuery. Awesomeness. So lets say we have the following action on our Employee controller:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public ActionResult LookupPeopleByZip(string zip)
{
	var peopleInZip = new List
		{
			new Person
				{
					Name = "John",
					Age = 25
				},
			new Person
				{
					Name = "Jane",
					Age = 30
				},
			new Person
				{
					Name = "Mike",
					Age = 21
				}
		};
 
	return Json(peopleInZip);
}

This creates a simple list of Person objects, uses the built-in ASP.NET MVC JSON result builder to serialize the object graph, and returns that JSON string. Now, let’s look at one possible, and probably more common, way to display these results in a table from an AJAX call:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<script type="text/javascript">
	$(document).ready(function() {
		$("#search").click(function() {
			var url = 'http://localhost:35125/Standard/LookupPeopleByZip/' + $("#zipCode").val();
 
			$.getJSON(url,
				function(allMatches) {
					var matchCount = 0;
 
					var tableHtml = '<table>' +
									'<tr>' +
										'<th>Name</th>' +
										'<th>Age</th>' +
									'</tr>';
 
					for (var i in allMatches) {
						matchCount++;
 
						tableHtml += '<tr>' +
									'<td>' + allMatches[i].Name + '</td>' +
									'<td>' + allMatches[i].Age + '</td>' +
								 '</tr>';
					}
 
					tableHtml += '</table>';
 
					var headerHtml = '<h3>Matches: ' + matchCount + '</h3>';
 
					$("#searchResults").html(headerHtml + tableHtml);
				});
		});
	});
</script>

When the search button is clicked, we use jQuery’s getJSON method to call out to our action depicted above. The resulting JSON string is constructed into an object graph and passed into our call back method (named allMatches above). We then piece meal our HTML together, looping through the object as needed and writing out the properties.

In the solution download at the end, you’ll see it runs just fine. Snappy and everything. Damn that’s some ugly Javascript code though, isn’t it? This is all for a very simple two column table - just imagine something of even moderate complexity here. Instead, let’s take a look at the jTemplates solution:

1
2
3
4
5
6
7
8
9
10
11
12
13
<script type="text/javascript">
	$(document).ready(function() {
		$("#search").click(function() {
			var url = 'http://localhost:35125/JTemplates/LookupPeopleByZip/' + $("#zipCode").val();
 
			$.getJSON(url,
				function(allMatches) {
					$('#searchResults').setTemplateURL('/Content/ResultTemplate.html');
					$('#searchResults').processTemplate(allMatches);
				});
		});
	});
</script>

Just a wee-bit smaller, wouldn’t you say? This code is mostly the same as the original, but instead of building the needed HTML template inline, it uses the jTemplates provided methods on the jQuery selector to set the location for our template, and execute it with our allMatches collection. The template referenced above, ResultTemplate.html, is a basic HTML snippet intermingled with a very minimalistic script like language that jTemplates parses out and updates appropriately:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<h3>Matches: {$T.length}</h3>
 
<table>
	<tr>
		<th>Name</th>
		<th>Age</th>
	</tr>
 
	{#foreach $T as match}
		<tr>
			<td>{$T.match.Name}</td>
			<td>{$T.match.Age}</td>
		</tr>
	{#/for}
</table>

The syntax is actually pretty similar to the Spark view engine. It simply loops through the passed in parameter ($T) and prints out the needed properties. Notice there’s a few extra properties dangling off the parameter too, such as length, used to show the match count at the top.

That’s pretty much the basics. Sort of an output only MVC pattern for Javascript (with the JSON return being the model, the return call method being the controller, and jTemplates providing the view engine). If you take a look through the jTemplates site you’ll see there’s quite a bit more to it if needed. Its come in handy in a few places on our project so far. Grab the sample solution here.

« Previous Entries