Search code examples
asp.net-mvc-4razordisplay-templates

MVC4 Razor DisplayTemplate called, HTML generated, but not rendered to browser


I've got a view that iterates a collection and calls DisplayFor() for each element in the collection.

I need to manually iterate (as opposed to passing the collection to DisplayFor) in order to tell the template if a break in the list should be drawn. The items in the list will only be of 2 types, ordered by them, so I only need to show this break once.

My template is found and called correctly.
I can see the HTML it generates correctly, ie: DisplayFor().ToHtmlString()
I can set this HTML as a scoped variable, ie: var html = DisplayFor().ToHtmlString() ..
But even Html.Raw(html) does not render it in the browser - the HTML has simply vanished.

What's going on?

var renderBreakInList = Model.Items.Any(x => x.IsSomeType);
foreach(var item in Model.Items)
{
    var renderBreak = renderBreakInList && item.IsOtherType;
    Html.DisplayFor(x => item, new { renderBreak = renderBreak });

    if (renderBreak)
    {
        renderBreakInList = false;
    }
}

Solution

  • The Html.DisplayFor method in itself does not render anything to the response just returns the generated HTML as a MvcHtmlString.

    In order to actually write the rendered HTML to the response you need to tell this to Razor with using the @ sign:

    @Html.DisplayFor(x => item, new { renderBreak = renderBreak })
    

    So your whole code should look like this:

    @{
        var renderBreakInList = Model.Items.Any(x => x.IsSomeType);
        foreach(var item in Model.Items)
        {
            var renderBreak = renderBreakInList && item.IsOtherType;
            @Html.DisplayFor(x => item, new { renderBreak = renderBreak })
    
            if (renderBreak)
            {
                renderBreakInList = false;
            }
        }
    }
    

    Or you can use the WebPageBase.Write method (which gets called under the hood when using the @ sign):

    Write(Html.DisplayFor(x => item, new { renderBreak = renderBreak }));