views:

5950

answers:

7

Here is a scenario: Let's say I have site with two controllers responsible for displaying different type of content - Pages and Articles. I need to embed Partial View into my masterpage that will list pages and articles filtered with some criteria, and be displayed on each page. I cannot set Model on my masterpage (am I right?). How do I solve this task using Html.RenderPartial?

[EDIT] Yes, I'd probably create separate partial views for listing articles and pages, but still, there is a barrier that I cannot and shouldn't set model on masterpage. I need somehow to say "here are the pages" as an argument to my renderpartial, and also for articles. Entire concept of renderpartial with data from database in masterpages is a bit blurry to me.

A: 

The ViewData Model property should only be used for the content that you're viewing/editing on the main section of the UI.

Other parts of the view may need some data present in ViewData, so just add those to the dictionary.

I'd just pass data from the dictionary like this: ViewData["articles"] to the partial. (or ViewData.Get() from MvcContrib).

You might also look at the recently implemented SubController pattern implemented in MvcContrib.

Ben Scheirman
A: 

yes, this is correct. but let's look at this scenario: on views that are related to articles, I'd have ViewData["article"], and on views related to pages, I have ViewData["pages"], but I don't have both articles and pages available all time. So, if I add:

Html.RenderPartial("articlesView", ViewData["articles"])

Html.RenderPartial("pagesView", ViewData["pages"])

to my masterpage, I'll have an exception thrown on each page on which ViewDataDictionary doesn't contain both articles and pages.

At least, that's how I see it.

Dragan Panjkov
+1  A: 

I had a similar post and came up with an object model to handle it.

I HATE the non-strongly typed views so went with this approach and it is working well.

Simon_Weaver
+2  A: 

How about creating an HtmlHelper extension method that allows you to call a partial view result on the an action on the controller.

Something like

 public static void RenderPartialAction<TController>(this HtmlHelper helper, Func<TController, PartialViewResult> actionToRender)
    where TController : Controller, new()
{
    var arg = new TController {ControllerContext = helper.ViewContext.Controller.ControllerContext};
    actionToRender(arg).ExecuteResult(arg.ControllerContext);
}

you could then use this in your master page like

<% Html.RenderPartialAction((HomeController x) => x.RenderPartial()) %>

and in your controller the appropriate method

public PartialViewResult RenderPartial()
{

     return PartialView("~/Path/or/View",_homeService.GetModel())
}

Well that is my 2 cents anyway

A: 

The way that I handle this is by using a BaseViewModel. All Views are strongly typed against a view model that inherits from BaseViewModel.

The BaseViewModel class has all of the information needed by the MasterPage. So for navigation your BaseViewModel may look like this:

public class BaseViewModel
{
    public BaseViewModel()
    {
         NavigationItems = RetrieveNavigationItemsFromModel();
    }
    public List<NavItems> NavigationItems {get; set;}
}

In your MasterPage and PartialViews, you can cast the Model to BaseViewModel and access the NavigationsItems property.

<ul>
<% foreach (NavItem ni in (Model as BaseViewModel).NavigationItems) { %>
    <li>
        <a href="<%= ni.Url %>" alt="<%= ni.Alt%>"><%= ni.DisplayText %></a>
    </li>
<% } %>
</ul>
Jeremy
+1  A: 

I think that your solution may lie in the land of MVC 2.0 RC and beyond...

Phil Haack posted an article on his blog: http://haacked.com/archive/2009/11/18/aspnetmvc2-render-action.aspx

Brett Rigby
A: 

This is a very late reply, but I got to this page whilst googling - so chances are someone else will see this question (and my reply) as well.

The way I've worked around this problem is by using a simple jQuery script to load a PartialView and execute it's controller code. Sample below.

<asp:Content ID="indexContent" ContentPlaceHolderID="MainContent" runat="server">

    <script type="text/javascript">
            $(document).ready(function() {
            $("#applicationForm").load("/Home/ApplicationForm");
            });
    </script>

    <div id="applicationForm" />

</asp:Content>

The big drawback to this approach is that the client has to have scripting enabled for it to work (so it's really SEO unfriendly). If that's something you can live with it works well. I only use it on an intranet site where I know that each client has JavaScript enabled and I don't have to worry about google's bots.

Ciddan