Monday, 8 November 2010

Spark and jQuery Templates learn how to play nice

A couple of folks are running into trouble while trying to use the recently popular jQuery Templates in combination with the Spark View Engine for one innocuous, simple reason – they both use the ${blah} syntax as placeholders for their magic bits. It is now gaining even more popularity due to Steve Sanderson’s AWESOME Knockout JS library and I’m not surprised – it seriously kicks ass!

I guess somebody didn’t really think the syntax through and have a good look at what was already out there, but I think it’s things like this that really test the metal of a framework in its ability to be flexible and co-exist happily with others. Getting them to play nice with as little friction for the developer is key in getting adoption up in all areas.

The Problem

For this post I’ll be using Rob Ashton’s RavenDB Gallery sample on github since it uses both Spark as a View Engine and jQuery Templates for loading images and details.

Take a look at this view:

<content name="title">Home Page</content>
<content name="scripts">
<script type="text/javascript" src="~/Includes/js/image-browser.js" ></script>
</content>
<h2>The RavenDB Image Gallery</h2>
<p>
This is an example ASP.NET MVC application using RavenDB,
MVC2, StructureMap, Moq and NUnit
</p>
<label for="searchText">Search</label>
<input type="text" id="searchText" name="searchText" />
<script id="browsing-image-template" type="text/x-jquery-tmpl">
<div class="browsing-image">
<h4>${Title}</h4>
<img src="/Resources/Image/${Filename}" alt="${Title}" />
</div>
</script>
<div id="image-browser">
</div>

Notice the highlighted lines above are referencing jQurey template values inside the ${ xyz } syntax. The issue here is that Spark gets the first stab at these files, and if it sees the ${ xyz } syntax, it tries to parse the view using the variable it knows about, which will either lead to unexpected results because you have the same variables defined in Spark and in jQuery.templ,  or it will fail completely due to a Spark dynamic view compilation error since it knows nothing about ${Title} or ${Filename}.

The Workaround

Now there are already a couple of workarounds that have been used. For example, by using jQuery to load up the templates via an AJAX call will bypass the Spark rendering engine unless it’s specifically a Spark Javascript View, but this means you take the asynchronous hit for something that might not be ideal. Another solution is to use the alternate jQuery Templates syntax which Spark doesn’t recognise. It looks like this: {{= Title }} … pretty ain’t it? Yeah…I didn’t think so either.

One Solution

Well of course the ultimate solution would be for the developer to just throw any old syntax in there and the collective frameworks just figure out which bits to parse and which bits to leave alone, but there are two reasons I didn’t want to try and achieve that. Firstly, the next guy who has to come and read your code may just decide it’s worth it to take a contract out on your life, and I don’t want to take responsibility for that :-). To work out programmatically what the developer wants is one thing, and in a way it’s a nice puzzle to solve, but working with and maintaining that code will not be a pleasant or intuitive experience.

Some might look at the view above and say that they don’t like the fact that a fat script tag has just dropped itself down in the middle our HTML mark-up without an invite. Heck, that’s going to make plenty of developers do a double-take – it’s just not natural and creates a disconnect in the flow of the code. Just like if someone decided to solve a complex algorithm inside an IF statement in the middle of a method, you would expect a good developer who cares about code maintainability and readability to extract that complexity into a different method right? Right?!

Well that’s basically what we’ve done as a first stab at supporting jQuery Templates. That same view above will simply be split into two files, kind of like extracting the complexity into it’s own method. We use an existing feature in Spark called the <include> tag and use the new parse=”html” option which basically passes the contents though without parsing for Spark variables or HTML encoding it. The result looks something like this:

 

image

Index.spark

<content name="title">Home Page</content>

<h2>
The RavenDB Image Gallery</h2>
<p>
This is an example ASP.NET MVC application using RavenDB, MVC2, StructureMap, Moq
and NUnit</p>
<label for="searchText">Search</label>
<input type="text" id="searchText" name="searchText" />

<include href="browsing-image-template.htm" parse="html" />

<div id="image-browser">
</div>

And the extracted file can be called anything you like, but as you can see, I’ve named it something useful and given it a “.htm” extension so that we get the benefits of the HTML editor in Visual Studio:

browsing-image-template.htm

<script id="browsing-image-template" type="text/x-jquery-tmpl">
  <div class="browsing-image">
    <h4>${Title}</h4>
    <img src="/Resources/Image/${Filename}" alt="${Title}" />
  </div>
</script>

As you can see now, we’ve also achieved some form of Separation of Concerns where the flow of the original mark-up is undisturbed, and the included template complexity gets its own space to operate in during the writing and maintenance of the code, but when come it comes to the browser requesting the view, it is fully rendered on the server and delivered in a perfect single HTTP stream with all the right bits falling in to the right places.

OK – Now gimmeh teh dllz

It just so happens that you can get the latest via the NuGet package manager direct in Visual Studio. If you just want the raw release package in a zip file, you can always download the latest from here and just login as an anonymous guest.

Conclusion

To be clear, this is only one way of achieving the solution, but I am keen to try it out on the audience that care because there is still a decent sized hole with this method. Namely, the question arises: What if you do want to use some Spark Variables inside your jQuery Templates? What if you do want the view engine to parse things inside there?

Well I’d like to see some examples of that before spending the time figuring out a more complex method of escaping, because I’m not entirely convinced that would be a good or maintainable design. I’m happy to be convinced otherwise, but for now I would suggest that this is a better way…

Until next time,
Robert The Grey

1 comments:

  1. Looks like your previous comment got swallowed mate - you'll have to drop it in an email or something if you were asking a question.

    Cheers,
    Rob

    ReplyDelete