Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

Lets say I am writing a blog web application using MVC pattern. Typical layout for the main page of the blog application is - some kind of a post index in the main part, and aside there are some addition parts, like timeline, tag navigation panel, subscribing panel, etc. Those controls also appear on a single post view, and may appear on other views I have.

My question is - how should I handle those panels aside in my views and controllers. I see three approaches here:

  1. Create a big viewmodel class that contains all the information required for rendering the view s (either index or single post). That case I could make these aside panels a partial views, and calling them from the view being rendered passing part of that big viewmodel. The drawback is - I will have the code filling viewmodel spread amongst various controller method, meaning code is duplicated. Which is quite bad.

  2. Create another layer of view rendering. Say, the topmost layer of rendering recives a alreay rendered parts of html, or functions which when called outputs an html. The layer under this "combining partials layer" would give just partial views for each panel I want, include main content. The drawback here - memory usage. Most modern frameworks renders htmls directly to output stream, but in this approach partial views would be rendered into string objects first - which leads to memory overhead.

  3. Use something like "RenderAction" from asp.net mvc, which calls a controller method from a view. I think this is a worst solution of 3 given, because it drops an MVC approach.

The question is not tied to any specific framework, I want to understand the general way of doing things like that.

UPDATE

After an answer given, I've found out that post is not clear. So reasonable update here:

Under viewmodel term I understand an object that contains all the data required to render a particular view.

All of three approaches involve building partial views with their own viewmodel. For example (using C# syntax):

class SinglePostViewModel {
  string Text {get;set;}
  string Title {get;set;}
  string Slug {get;set;}
  DateTime PublishedDate {get;set;}
  ...
}

class TagNavigationPanelViewModel {
  string TagText {get;set;}
  int PostsCount {get;set;}
}

class CalendarNavigationPanelViewModel {
  DateTime YearAndMonth {get;set;}
  int PostsCount {get;set;} 
}

My question is - how to nicely combine those partial views together.

share|improve this question
add comment

3 Answers

I see another method that, unless I've misunderstood your post, hasn't been mentioned:

The main view, post, would have its model. This model would consist of ONLY the properties necessary to display this post (author,title,body, etc). Then, every piece of the post view that you can think of (timeline, tag navigation panel, subscribing panel, etc), would be split into their own views and each one would have its own model. This way, you can build up those models in your controller when you need them.

It might sound like an unnecessary amount of extra work to split these out like this, but it lends itself to the single responsibility principle. Keep each "view/model" focused on itself so that it can be re-used anywhere it is needed.

If you feel that your code is beginning to duplicate itself, which it might depending on your situation, you should consider writing some sort of "helper class." This helper class would handle all of the model build-up in one place, and all other duplicate code would be stripped down to a helper class call.

share|improve this answer
    
This is a general approach I try to follow. My question was about how to combine these partial views with own models together. Still I would update the question to make it more clear. –  Hedin Aug 8 '13 at 5:13
1  
I see...sorry for the initial confusion. I'd go with the container view that houses all of the necessary partial views, personally. –  ethorn10 Aug 8 '13 at 12:26
add comment

What I am doing is a variation/combination of your points 1 and 3. I combine the viewmodels in a container class, and use that as a "main" viewmodel. The pass the parts as models to the partials.

Following your example, I would create this viewmodel for the default page:

class DefaultViewModel {
  public List<SinglePostViewModel> Posts ...
  public TagNavigationPanelViewModel Tags ...
  public CalendarNavigationPanelViewModel Calendar ...
  ...
}

In Default.cshtml

@model DefaultViewModel
...html for rendering the default page...


@Html.Partial("_TagNavigationPanel", Model.Tags)
...etc...

In _TagNavigationPanel.cshtml

@model TagNavigationPanelViewModel
...html+razor for rendering the tags...

Then, follow the same approach for a single post page:

class SinglePostPageViewModel {
  public SinglePostViewModel Post ...
  // no tags in single view, for example..
  // public TagNavigationPanelViewModel Tags ...
  public CalendarNavigationPanelViewModel Calendar ...
  // But a list of related, perhaps?
  public List<RelatedPosts> RelatedPosts
  ...
}

And build your views (cshtml(s)) accordingly

share|improve this answer
    
This is what 1 approach is about. 3rd is only about calling RenderAction or @Html.Action, which involves calling the controller method. Thanks for reply! –  Hedin Aug 8 '13 at 8:15
1  
@Hedin oh, ok... I thought that your approach #1 was more "monolithic", with one big (different) viewmodel. So yes, I use 1 and find it good. I also like the third one less but it is good wrt caching. If you have performance issues, or need to cache parts of the view, it may be worth trying it. –  Lorenzo Dematté Aug 8 '13 at 13:16
add comment

You may create a single "container" view with all three subviews - SinglePostView, TagNavigationPanelView and CalendarNavigationPanelView. You can also replace the SinglePostView with any other view a page requires. This way you need only replace the "central" (post) view for different pages with another type of view (for example list of posts) and the other views just need to be updated with the corresponding data, not replaced.

Your container view (for example MyView) should hold references to all subviews. It may have different update methods that are used to update different subview. For example - updateCalendar(CalendarNavigationPanelViewModel calendarData) or updatePost(SinglePostViewModel postData). Or even a single update(IViewModel modelData) - then you'll need to check the type of (and cast) the modelData to determine which view to update

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.