Skip to main content
Home  ›  Blog

Razor Tip of the Day - Share Sub-Views Across Views (200)

Very often you'll have a larger system containing 2-10 views, which then again need to re-use parts of each other. For example, re-using an "Author" template in a blog for the list, details, search-by-author and search-by-tag views. Here's how.

The Basic Partial-Template/View

In general, you just place your sub-snippet in an own file (remember to prefix the name with a "_" for security reasons). If this partial template doesn't need any parameters passed in, then it's just like any razor file. Here's an example:

Extract of the _pager.cshtml

<nav>
    <ul class="pagination">
        <li @Html.Raw(pageNumber < 2 ? "class='disabled'" : "")>
            <a href="@lib.LinkToPageNumber(pageNumber - 1)" title="Zur&uuml;ck">
                <span aria-hidden="true">&laquo;</span>
            </a>
        </li>
        @for (var i = 0; i < pageCount; i++)
        {
            <li @Html.Raw(pageNumber == (i + 1) || (pageNumber == 0 && i == 0) ? "class='active'" : "")>
                <a href="@lib.LinkToPageNumber(i + 1)">@(i + 1)</a>
            </li>
        }
        <li @Html.Raw(pageNumber == pageCount ? "class='disabled'" : "")>
            <a href="@lib.LinkToPageNumber(pageNumber == 0 ? 2 : pageNumber + 1)" title="Weiter">
                <span aria-hidden="true">&raquo;</span>
            </a>
        </li>
    </ul>
</nav>

Passing in Parameters or Data

There are two different ways the sub-template can pick up data.

  1. In the first case, the sub-template just "knows" what data is to be used, based on the situation / master template it's in. For example the blog-app has a pager sub-template, which just expects that the views Data["Pager"] should contain everything it needs.
  2. In the second case the sub-template should be used like a function, expecting a few parameters (like data, color, repeater-parameters etc.) and would then behave differently. In the blog-app this happens for the list-item template, which shows 1 blog-post in a list-view. So this item is called for every list-item, and should of course receive the data to be rendered in the call

To the right you see the calling code, once with parameters (the post), once without. The two snippets below show

  1. Part of the _pager.cshtml, which just expects global data
  2. Part of the _list-item.cshtml, which needs to know which item to render

part of _pager.cshtml expecting global data

@* Paging Bar *@
@{
	// retrieve paging infos from the data-stream called "Paging"
    var pageInfo = AsDynamic(Data["Paging"]).First();
    int pageNumber = (int)pageInfo.PageNumber;
    int itemCount = (int)pageInfo.ItemCount;
    int pageSize = (int)pageInfo.PageSize;
    int pageCount = (int)Math.Floor((decimal)(itemCount + pageSize - 1) / pageSize);
}

@if (itemCount > pageSize)
{
    ...
}

Part of the _list-item.cshtml expecting parameters

@{	var lib = CreateInstance("_library.cshtml"); }
@{
	var post = PageData["Post"];
    var author = (post.Author.Count > 0) ? post.Author[0] : lib.unknownAuthor;
}
    <article class="app-blog-item">
        <div class="app-blog-col1 sc-element">
		@post.Toolbar
        ...
    ...
}

tl;dr

So that's it. In case you liked this, you may also like the tip on sharing functions / properties across views

Love from Switzerland,
Daniel 


Daniel Mettler grew up in the jungles of Indonesia and is founder and CEO of 2sic internet solutions in Switzerland and Liechtenstein, an 20-head web specialist with over 800 DNN projects since 1999. He is also chief architect of 2sxc (see github), an open source module for creating attractive content and DNN Apps.

Read more posts by Daniel Mettler