Templates With Razor

Razor is a great way to create views with ASP.NET MVC. One feature I use quite often are custom helpers. Instead of duplicating the same few lines of markup I simply create a reusable helper to generate HTML.

For example, you could create a helper to do something simple like render out a series of values...

@helper tabs(params Tab[] tabs) {
<ul>
  @foreach(var tab in tabs) {
  <li><a href="@tab.Url" >@tab.Text</a></li>
  }
</ul>
}

Then use the helper by providing the parameters it needs...

@tabs(new Tab { Text = "Google.com", Url = "http://google.com" },
  new Tab { Text = "Hugoware.net", Url = "http://hugoware.net" },
  new Tab { Text = "HerdingCode.com", Url = "http://herdingcode.com" })

This works pretty well for the most part but it is pretty limited in what it can do. Lets look at another approach.

Providing A 'Template'

In the previous example values were passed into the helper and used to generate the markup required. This time, the helper accepts slightly different arguments that will allow a bit more control.

@helper dialog(string title, Func<object, object> content) {
<div class="dialog-box" >
  <h3>@title</h3>
  <div class="dialog-box-content" >
    @content(null)
  </div>
</div>
}

This example uses a simple lambda (Func) as an argument to provide markup to render. This allows the Razor block (@...) to be passed in as an argument for the helper.

@dialog("User Status", 
    @<strong>User is offline!</strong>)

Now, the content is generated by an external source!

Using Types With Your Templates

So far the examples have used Func<object,object> as a template argument and then invoked the method with null as the argument. As it turns out, not only can you provide a value for that argument, if the argument type for the Func<...> is provided then it can be used from within a template.

@helper user_status(IEnumerable<User> users, 
  Func<User, object> online, 
  Func<User, object> offline) {

  <div class="user-status-list" >
      <div class="user-status" >
      @foreach(var user in users) {
          <h3>@user.Username</h3>

          if (user.IsOnline) { @online(user); } 
          else { @offline(user); }
      }
      </div>
  </div>
}

The helper above passes each User into the correct template. Now, a User can be referenced by using item from within the template.

@user_status(users,     
    online:@<div class="user-online" >
        User @item.Username is online!
        </div>,

    offline: @<div class="user-offline" >
        User @item.Username is offline!
        <a href="#" >Send a message!</a>
        </div>)

Now, the contents of each template is unique to the User that was provided!

August 12, 2011

Templates With Razor

Examples for using templates as parameters with helpers in Razor.