Templating unbalanced tags in the Razor Mediator
I've recently started using the Razor Mediator for Tridion (http://code.google.com/p/razor-mediator-4-tridion/) on a project, and it's been an interesting experience. To be honest, I wondered at first whether it would shift my views further in the direction of putting code in the templating layer, but I suspect I'll probably remain a die-hard token replacer. I did start at first with writing rather more C# in my templates than I generally would, but the reality is that the complexity always increases, and pretty soon you find yourself wanting to debug the code in Visual Studio. Then I'd rather have it in an assembly of its own. (OK - maybe there are, or could be, techniques for debugging your code in-place in the Razor template, but I'm not sure if the game would be worth the candle.)
Having said that, a few simple loops and if-blocks should be perfectly OK in the templating layer, which brings me to the subject of this post. My design has a page template which manages a list, in which the <li/> elements are created by a component template. The responsibility for the <ul/> belongs in the page template. (Yes - I know, but I've thought about it, and for what I'm trying to do, this is what makes the most sense.) So what about the scenario where they don't place any of the relevant component presentations on the page? Then I don't want the <ul> or the </ul> either. So I looked at the examples, and found how to do an if-block. How hard can it be, right? But this was where I hit another of my #babysteps learning points, which I'd like to share.
If you want to have an entire feature of your page appear or disappear based on a condition, you can simply write something like:
@if (someCondition) { <h1>The condition was met. Yeehah!</h1> }
Straightforward enough: you can just put your desired html output in your block, and it appears or doesn't depending on the condition. And at this point I was in full-on how-hard-can-it-be hubris-mode, cruising for a bruising and headed for a fall. Ok - let's go:
@{ var documents = @GetComponentPresentationsByTemplate("My Documents CT"); } @if (documents.Count > 0) { <ul class="lookListy"> } @foreach (var cp in documents) { @cp.RenderComponentPresentation() } } @if (documents.Count > 0) { </ul> }
... or something similar. Looks reasonable, eh? (OK - maybe with a bit of practice I can get that tidier.) Except it's not. It doesn't compile, or more specific, the C# generated by Razor doesn't compile, and in Tridion, all you see is a nasty message about the wrong number of curly brackets or semicolons or some such. It doesn't really matter much what the error is, because the structure of your code is broken, and the thing it's reporting is further down, and somewhere in the generated code anyway.
Nota Bene: This level of error reporting is reason enough to avoid doing any complex logic in your template. Put it in a class, for goodness' sake!
So what was the problem? It turns out that to put HTML in-line in a Razor block, the tags need to balance, so you can say
<ul>.... <./ul>
, but not an opening
<ul>
without the closing tag.
This is not an issue with razor-mediator-4-tridion per se, but rather one with the way Razor itself works. Still - to do a successful Razor templating implementation in Tridion, you'll almost certainly need to know it. The solution is simple: you just need to wrap your unbalanced tags in a <text/> wrapper, as follows:
@{ var documents = @GetComponentPresentationsByTemplate("My Documents CT"); } @if (documents.Count > 0) { <text><ul class="lookListy"></text> } @foreach (var cp in documents) { @cp.RenderComponentPresentation() } } @if (documents.Count > 0) { <text></ul></text> }
This will now compile correctly, and produce the desired result.
Thanks to the contributors over at http://code.google.com/p/razor-mediator-4-tridion/. It's a great project, and I can see lots of potential for using it in my own work. Much as I'm a fan of XSLT for other uses, in templating its verbosity tends to make people push important code out of view, and well... Dreamweaver syntax ain't pretty either. :-)
EDIT: Thanks to a suggestion by Neil Gibbons (Thanks Neil!) I now realise that if you nest the foreach inside the if (which works for the logic I was trying to achieve), the <ul/> is now seen as 'balanced' and doesn't need the <text.> wrapper. So the problem is less severe than I had thought, but it's still one you need to be aware of.
@{ var documents = GetComponentPresentationsByTemplate("My Documents CT"); if (documents.Count > 0) { <ul class="lookListy"> @foreach (var cp in documents) { @cp.RenderComponentPresentation(); } </ul> } }