Search code examples
asp.net-mvcasp.net-mvc-3razorpartial-views

How can I pass HTML content to a Partial View in MVC-Razor like a "for" block


I'm using Chromatron theme for an admin panel in my application. There is a sidebar gadget that has HTML content and with a little CSS trick it can be shown completely different.

<section class="sidebar nested">
    <h2>Nested Section</h2>
    <p>Lorem ipsum dolor sit amet, conse ctetur adipiscing elit. Maec enas id augue ac metu aliquam.</p>
    <p>Sed pharetra placerat est suscipit sagittis. Phasellus <a href="#">aliquam</a> males uada blandit. Donec adipiscing sem erat.</p>
</section>

I want to have a Partial View that is used like this:

@Html.Partial("Path/To/Partial/View"){
    <h2>Nested Section</h2>
    <p>Lorem ipsum dolor sit amet, conse ctetur adipiscing elit. Maec enas id augue ac metu aliquam.</p>
    <p>Sed pharetra placerat est suscipit sagittis. Phasellus <a href="#">aliquam</a> males uada blandit. Donec adipiscing sem erat.</p>
}

TBH, I want to have functionality like I have in a @for(...){ } block. Is this possible in Razor?


Solution

  • I was having the same dilemma. Try creating a viewmodel type with a Func property and then pass the html as delegate.

    public class ContainerViewModel
    {
        public String Caption { get; set; }
        public String Name { get; set; }
        public Int32 Width { get; set; }
        public Func<object, IHtmlString> Content { get; set; }
    }
    
    @Html.Partial("Container", new ContainerViewModel()
    {
        Name = "test",
        Caption = "Test container",
        Content =  
        @<text>
           <h1>Hello World</h1>
        </text>,
        Width = 600
    })
    

    You can call it like this in your partial.

    @Model.Content(null)
    

    If you want to be fancy you can add this extension method.

    public static class PartialExtensions
    {
        public static IHtmlString Display<T>
            (this T model, Expression<Func<T, Func<Object, IHtmlString>>> content) 
        {
            var compiled = content.Compile();
            return compiled.Invoke(model).Invoke(null);
        }
    }
    

    Then, any time you use this pattern, you can call it like this in your partial (not fully tested).

    @model ContainerViewModel
    @Model.Display(m => m.Content)  // Use delegate property
    

    Hope this works for you.

    It works because the @... syntax creates a little HtmlHelper for you that consumes a Model (which you're declaring here as type object, and passing null for), and returns an IHtmlString.

    BEWARE form values don't seem to post to the server if @Html.BeginForm is used in the content.

    Therefore, wrap your form around the container.