Skip to content. | Skip to navigation

Personal tools

Navigation

You are here: Home / weblog

Dominic Cronin's weblog

Showing blog entries tagged as: Razor templating

The Razor Mediator for Tridion - in practice

Most of my blog output is to be found right here, but this week I published an article on the Indivirtual web site.

http://inside.indivirtual.nl/2013/10/the-razor-mediator-for-tridion-in-practice/

The article goes into the background of the Razor Mediator for Tridion, and our thinking behind using it on a customer project. I hope you find it interesting.

Using helpers in Tridion Razor templating

Today, for the first time, I used a helper in a Razor Tridion template. I'd made a fairly standard 'generic link' embedded schema, so that I could combine the possibility of a component link and an external link in a link list, and allow for custom link text. (Nothing to see here, move along now please.)  However, when I came to template the output, I wanted to have a function that would process an individual link. A feature of Razor templating is that you can define a @helper, which is a bit like a function, except that instead of a return value, the body is an exemplar of the required output. There is also support for functions, so to lift Alex Klock's own example:

@functions {
    public string HelloWorld(string name) {
        return "Hello " + name;
    }
}

and

@helper HelloWorld(string name) {
    <div>Hello <em>@name</em>!</div>
}

will serve fairly similar purposes.

What I wanted to do today, however was slightly different; I didn't want to pass in a string, but a reference to my embedded field. All the examples on the web so far are about strings, and getting the types right proved interesting. I started out with some code like this:

@foreach(var link in @Fields.links){
  @RenderLink(link);
}

So I needed a helper called RenderLink (OK - this might be a very trivial use-case, but a real problem all the same.). But what was the type of the argument? In theory, "links" is an EmbeddedSchemaField (or to give it it's full Sunday name: Tridion.ContentManager.ContentManagement.Fields.EmbeddedSchemaField) but what you get in practice is an object of type "Tridion.Extensions.Mediators.Razor.Models.DynamicItemFields". I'd already guessed this by poking around in the Razor Mediator sources, but after a few of my first experiments went astray, I ended up confirming that with @link.GetType().FullName

Well I tried writing a helper like this:

@using Tridion.Extensions.Mediators.Razor.Models 
@helper RenderLink(DynamicItemFields link){
... implementation
}

but that didn't work, because when you try to call the methods on 'link' they don't exist.

And then, just for fun, of course, I tried

@using Tridion.ContentManager.ContentManagement.Fields 
@helper RenderLink(EmbeddedSchemaField link){
... implementation
}

but that was just going off in an even worse direction. Yeah, sure, that type would have had the methods, but what I actually had hold of was a DynamicItemFields. Eventually, I remembered some hints in the mediator's documentation and tried using the 'dynamic' keyword. This, it turns out, is what you need. The 'dynamic' type lets you invoke methods at run-time without the compiler needing to know about them. (At last, I was starting to understand some of the details of the mediator's implementation!)

@helper RenderLink(dynamic link){
... implementation
}

This may be obvious with hindsight (as the old engineers' joke has it ... for some value of 'obvious') . For now, I'm writing another blog post tagged #babysteps and #notetoself, and enjoying my tendency to take the road less travelled.

TWO roads diverged in a yellow wood,
And sorry I could not travel both
And be one traveler, long I stood

And looked down one as far as I could


To where it bent in the undergrowth;
Then took the other, as just as fair,
And having perhaps the better claim,

Because it was grassy and wanted wear;


Though as for that the passing there
Had worn them really about the same,
And both that morning equally lay

In leaves no step had trodden black.


Oh, I kept the first for another day!
Yet knowing how way leads on to way,
I doubted if I should ever come back.

I shall be telling this with a sigh


Somewhere ages and ages hence:
Two roads diverged in a wood, and I—
I took the one less traveled by,
And that has made all the difference.

-- Robert Frost

Templating unbalanced tags in the Razor Mediator

Posted by Dominic Cronin at Nov 17, 2012 05:30 PM |

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>
    }
  }