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 = "LosTechies.com", Url = "https://lostechies.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<object, object>) 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!

Joining Los Techies!