Prerender AngularJs templates with MVC HTML helpers

As a .NET Web developer, I'm always looking for better ways to get Angular and MVC.NET to play nicely together. Writing and rendering templates using the templateCache is a good example of these two world that tend to collide if not implemented correctly.

Why

Best Practice: Unless your template is very small, it's typically better to break it apart into its own HTML file and load it with the templateUrl option.

So this is not recommended:

directive('toggleButton', function () {
    return {
        replace: true,
        template: '<div style="float:left; cursor:pointer;">' +
                    /* ...Template Html ...  */ 
                  '</div>'
    }     
});

It is recommended to place the above HTML string in a separate (cshtml) file..

I want to keep enjoying razor features like translations, Urls, model rendering though. And I don't want to serve these HTML files through Ajax either. Everything has to be rendered in the initial request.

To do this, Razor's RenderPartial comes into play.

The HTML Helper

I tend to be a DRY developer :). I am not going to write a script tag with a RenderPartial implementation for each template I define in my angular module. So I created an HTML helper that would be able to do the heavy lifting for me.

Create an 'HtmlHelpers.cshtml' file in the 'App_Code' folder of your solution, and paste the following code:

@helper RenderTemplates(string folderPath, string targetPath, params string[] excludedUrls)
{
  var folder = Server.MapPath(folderPath);
  var rootFolder = Server.MapPath("~/");
  var dir = new DirectoryInfo(folder);
  var urls = dir.GetFiles("*.cshtml", SearchOption.AllDirectories).Where(x => !excludedUrls.Contains(x.FullName));
  foreach (var url in urls)
  {
    var target = targetPath + "/" + url.Name;
    <script type="text/ng-template" id="@target" class="ng-cloak">
    @WebPageContext.Current.Page.RenderPage(string.Format("~/{0}", url.FullName.Remove(0, rootFolder.Length).Replace('\\', '/')))
    </script>
  }
}

This will allow you to call the RenderTemplates method in any razor page like this:

 @HtmlHelpers.RenderTemplates("~/app/modules/calendar/shared/templates", "/app/calendar")

The 'folderPath' variable identifies the folder on the server that contains your Angular template files. The 'targetPath' variable allows you to prefix the template names, which will allow you to identify the templates more easily.

The RenderTemplates method should now output something like the following HTML code:

    <script type="text/ng-template" id="/Angular/calendar/event.cshtml" class="ng-cloak"> 
        /* ...Template Html ...  */
    </scipt>

You can now use this rendered template in your directive using the provided id, like this:

directive('toggleButton', function () {
  return {
    templateUrl: '/Angular/calendar/event.cshtml'
  }
});

You might enjoy


We've all been there at some point. Your app works great on your machine, all features are ready to…

I recently experienced a confusing, head-ache-causing problem while deploying an MVC application to a Windows Server 2008. The issue…

Tim Sommer

I'm a Web Developer with +7 years of experience in the .Net framework, with a focus on HTML5 and JavaScript.

Belgium, Antwerp
comments powered by Disqus
OWIC
Member of The Internet Defense League