views:

130

answers:

4

I have a single view which has a menu on the left hand side and a container on the right hand side that is rendered from one of several partial views.

Right now I'm running into a situation like the following "Index" view:

<div class="container">  
    <div class="leftHandMenu">  
        // various dynamic menu items  
    </div>  
    <div class="rightHandPane">  
        <% if (Model.CurrentPane == "Sent") { %>  
            <% Html.RenderPartialView("SentPartial", Model.SomeData);  %>  
        <% } else if (Model.CurrentPane == "Inbox") { %>   
            <% Html.RenderPartialView("InboxPartial", Model.SomeData);  %>  
        <% } else if (Model.CurrentPane == "Alerts") { %>  
            <% Html.RenderPartialView("AlertsPartial", Model.SomeData);  %>  
        <% } %>  
    </div>  
       // various other common view items  
</div>

with the following actions:

public ActionResult Inbox(int? page)  
{  
    MessageListViewModel viewData = new MessageListViewModel();
    viewData.SomeData = messageService.getInboxMessages(page.HasValue ? page.Value : 0);
    viewData.CurrentPane = "Inbox";
    return View("Index", viewData);
}  

public ActionResult Alerts(int? page)  
{  
   MessageListViewModel viewData = new MessageListViewModel();
    viewData.SomeData = messageService.getAlertMessages(page.HasValue ? page.Value : 0);
    viewData.CurrentPane = "Alerts";
    return View("Index", viewData);
} 

public ActionResult Sent(int? page)  
{  
    MessageListViewModel viewData = new MessageListViewModel();
    viewData.SomeData = messageService.getSentMessages(page.HasValue ? page.Value : 0);
    viewData.CurrentPane = "Sent";
    return View("Index", viewData);
}

I realize this situation isn't ideal, but I need those portions to remain partial views. I'm doing a bunch of ajax calls on this view to reload that "rightHandPane" with the various partial views.

I have a single view "Index", and then these various partial views which load a particular pane of "Index". I'm passing in the view name into the ViewModel, and then have these if-else statements loading in the appropriate partial view.

How else could I be doing this? I'm about to add 3 more partial views and this is starting to be a pain. I'd prefer if I didn't have to maintain my currentPane in my ViewModel at all really.

Is there something I can do to avoid this situation all-together? I've considered using a Master View for the common portions but I need it to be a strongly typed Master View, which isn't that easy in ASP.NET MVC.

Thanks!

A: 

You could either

a) (if you're using, or will be using, ASP.NET 4) add a call to Html.Action() or Html.RenderAction() instead, and let the controller action decide which partial to render.

b) factor out the if-statements to a separate partial, or to a helper method. For example:

public static void RenderRightHandPane(this HtmlHelper helper, YourViewModelType model)
{
    switch(model.CurrentPane.ToLower())
    {
        case "sent":
            helper.RenderPartialView("SentPartial", model.SomeData);
        case "inbox":
            helper.RenderPartialView("InboxPartial", model.SomeData);
        case "alerts": 
            helper.RenderPartialView("AlertsPartial", Model.SomeData);
        case default:
            // Add a default handler - perhaps rendering a not found-view...?
    }
}

that is called like so:

<% Html.RenderRightHandPane(Model); %>
Tomas Lycken
+2  A: 

Why not use separate views for each actions with a master page taking care of all the common bits?

You can have a master page with a place holder for each section.

<div class="container">  
    <div class="leftHandMenu">  
        <asp:ContentPlaceHolder ID="LeftHandMenuContainer" runat="server" />
    </div>  
    <div class="rightHandPane">  
         <asp:ContentPlaceHolder ID="RightHandPaneContainer" runat="server" />
    </div>  
      <asp:ContentPlaceHolder ID="FooterContainer" runat="server" />  
</div>

Then put view specific contents in each content page.

Mark
Well, some of the common bits are dynamic. I'd need a strongly typed master view. I can't do that without creating some Base controller, right?
KingNestor
The master page can have several different content placeholders where you could put your area specific content. ....I'll add to my answer.
Mark
The pattern is known as view composition and is the correct way of solving this problem. Factor out the common stuff into a layout and compose the view from the necessary partials using the layout to define the structure.
Neal
+1  A: 

You could simply write:

Html.RenderPartialView(string.Format("{0}Partial", Model.CurrentPane), Model.SomeData);  %>

but I would recommend you pass the name of the entire Partial View. My $.02.

hunter
A: 

You could "code by convention" and follow this pattern:

<div class="rightHandPane">  
    <% Html.RenderPartialView(Model.CurrentPane + "Partial", Model.SomeData);  %>  
</div>
Jason