How much code is acceptable in a View? - asp.net-mvc

I was wondering how much code is acceptable in a view ? It is acceptable to use foreach or if such if a list of items is empty.. show some message ? or should this be done in the controller ?

in a really few works
The View should containt all the code you need for your presentation logic even ForEach (if you need them)
Some people like to create HTML helper to split down the presentation logic and inclapsulate it into an adhoc method
The control should be very skinny: it should just get the user interaction and delegate them to the right component. It may contain some validation logic (user input etc) but it really depends by your business requirements

Rushino,
To address the specific example that you cite. For a list of items, I'd be tempted to include a strongly typed helper in the view that either returned the appropriate list OR simply returned an empty MvcString. As for other logic in the view, i'd keep it to a minimum as you quickly run out of options for unit tests once the view is littered with case statements and ifs and buts. Of course, there will be occasions where the judiciuos use of a few varables may be acceptable, but few and far between.
just my 2 cents

Related

ASP.NET MVC - How to best build a form action that can respond in many ways?

I am in the process of writing a web app that includes a reporting form. This form contains a number of radio buttons that allow the user to specify the return data.
There are about 6 different return data 'formats', and each of those has two variations - html data or JSON data for rendering to a chart.
I have begun coding it up and already my form post action method feels wrong.
I basically have a check on the requested data format and return it as needed. Each return type requires its own partial view / json object so there is little room for reusing code.
It feels like each one should have its own action method. Having the form post to different locations based on a radio button choice also feels wrong though.
Switching on report type and then redirecting to the appropriate action in the controller also feels like its not quite right.
Am I approaching this in the wrong way? As it currently stands my controller action contains a lot of code and a lot of logic...
Hope my query makes sense.
Thanks
I don't think there is anything wrong with your approach. To maximize reuse you could:
include reusable templates inside your views
make sure the business/data layer code is the same everywhere (where possible)
I suppose the views you need to return actually are different for each combination of options so whatever approach you take, you are stuck with that.
I wouldn't opt for the client-side approach. You then have code on both the server and the client that has to be updated whenever you change anything. I would keep the code that receives a set of options and determines what to do with them in one place.
I know what you mean about it feeling like each format should be a separate action, but maybe a hybrid approach would make it feel better.
If you set the value of each radiobutton to the name of the action it relates to, you then, in your main POST action, have a parameter that you can use to call the appropriate action in one line of code. You don't have to fudge anything in Javascript, it's easily extensible, and you get your separate actions.
If I understand your problem right you have a lot of switch code in action.
I think you can use Factory pattern. You can create factory that will accept switch parameter as parameter and will return ActionResult instance.

Exporting ViewData\ModelState to Child Action

As the subject says, is this a bad idea? If so, why?
Currently, if you are rendering some input fields from inside a #Html.Acion, the validation errors don't get displayed to the user as the ModelState gets cleared when the #Html.Action gets involved (in its context.)
So whats the best pattern around it?
You can access the parent contexts via ControllerContext.ParentActionViewContext or ViewContext.ParentActionViewContext (details here) but I think there are better solutions.
A child action is a good choice when you do not want to pollute all of your view models with data which are available independent from the current controller action and view (for example a user welcome label, a navigation bar, etc.).
For other reuse scenarios like common input fields a partial view is a better approach.
However if you give more details about your current scenario I try to suggest a more specific solution.

Should the model be responsible for holding lists that will ultimately populate dropdownlists in the view?

This might be similar to ASP.NET MVC - Populate Commonly Used Dropdownlists.
I want to populate DropDownLists. Some of it is static data. Some of it comes from the Database. A couple of times I found myself forgetting to call the code that populates my lists and sets the ViewBag accordingly. It is almost worth adding a unit test for this. The only way I think that this suits a unit test is if you place it in model/service. Is there a best practice for this kind of thing?
I'd suggest that the data is contained within the model but is perhaps constructed by a html.helper method. this way, you keep the plumbing markup out of the view and leave the controller free to invoke the neccesary view and model.
You could also of course hand it off to a partialview with an <IList<SelectList>> model.
cats and their skin :)
If you follow the spirit of the pattern then the Model should supply the View with everything it needs to present to the user that's not static. If you have static dropdown lists then you could say that these could be constructed within the mark-up. If you are passing a SelectList to the View from your Action then I'd stick it in the Model to make things simpler and more coherent.
My rule of thumb is that the data must somehow be in the model, either as a ready to use SelectList or at worst in some container that can easily be turned into a SelectList using a LINQ-to-object call.
The bottom line is that the view should never contain any non trivial code.
EDIT (answer to your comment):
I try not to put too much code in models. Models are more like a simple bunch of data gathered by the controller and used by the view.
Regarding simple and/or common things such as the days of week, I believe an HTML helper is the most elegant solution. See WayneC's answer in this question.

When is it right to use ViewData instead of ViewModels?

Assuming you wanted to develop your Controllers so that you use a ViewModel to contain data for the Views you render, should all data be contained within the ViewModel? What conditions would it be ok to bypass the ViewModel?
The reason I ask is I'm in a position where some of the code is using ViewData and some is using the ViewModel. I want to distribute a set of guidelines in the team on when it's right to use the ViewData, and when it's just taking shortcuts. I would like opinions from other developers who have dealt with this so that I know my guidelines aren't just me being biased.
Just to further Fabian's comment; you can explicitly ensure viewdata is never used by following the steps outlined in this article. There's really no excuse not to use models for everything.
If you have no choice but to use ViewData (say on an existing project); at the very least use string constants to resolve the names to avoid using 'magic strings'. Something along the lines of: ViewData[ViewDataKeys.MyKey] = myvalue; Infact, I use this for just about anything that needs to be "string-based" (Session Keys, Cache Keys, VaryByCustom output cache keys, etc).
One approach you may wish to consider as your views become more complex, is to reserve the use of Models for input fields, and use ViewData to support anything else the View needs to render.
There are at least a couple of arguments to support this:
You have a master-page that requires some data to be present (e.g. something like the StackOverflow user information in the header). Applying a site-wide ActionFilter makes it easy to populate this information in ViewData after every action. To put it in model would require that every other Model in the site then inherit from a base Model (this may not seem bad initially, but it can become complicated quickly).
When you are validating a posted form, if there are validation errors you are probably going to want to rebind the model (with the invalid fields) back to the view and display validation messages. This is fine, as data in input fields is posted back and will be bound to the model, but what about any other data your view requires to be re-populated? (e.g. drop-down list values, information messages, etc) These will not be posted back, and it can become messy re-populating these onto the model "around" the posted-back input values. It is often simpler to have a method which populates the ViewData with the..view data.
In my experience I have found this approach works well.
And, in MVC3, the dynamic ViewModels means no more string-indexing!
I personally never use ViewData, everything goes through the Model, except when im testing something and i quickly need to be able to see the value on the view. Strongtyping!
In terms of ASP.NET MVC 2, ViewModel pattern is the preferred approach. The approach takes full advantage of compile time static type checking. This in combination with compiling mvc views will make your development work-flow much faster and more productive since errors are detected during build/compile time as opposed to run time.

How much logic do you put in views?

I am currently unconfident, if I can put a "if/else"-construct into my view?
How much logic do you put in your views?
My dilemma:
I am rendering a navigation. So, I have to differ between the current/active menu item and the rest. The current menu item gets a special css class. I don't know how to handle this in a better way than using if-else.
If you are doing MVC (hopefully you do), than the question is "Do I put the logic in the view or the controller?". I use a simple rule to find out the answer of that:
What if my view was not HTML, but an XML document?
If I will need this logic in both circumstances - its place is in the controller. If not - it's in the view.
In good MVC design you should be able to swap the views without touching the controller.
As much as is necessary to display the information. Just remember that the view is just a window into the internal state of the program. If you stripped the view layer completely away, the program should still be able to operate as usual, just without being able to see what it's doing.
edit: re your navigation, that seems like an okay use of an if statement. The information about which is active is still coming from the model, you're simply using the if statement to decide how to display it. You might consider a little bit about how you're rendering your navigation: is the information about which navigation items available, and which to render living in your view or your model?
One way you might choose to approach the situation is to have the model give you a list of navigation items, along with which one is active, and program the view to know how to generate appropriate HTML from that. That code might contain precisely one if statement total. (instead of one for each nav item).
I wouldn't worry about putting an if statement in a view. In fact, I think there's a bit too much hand-wringing (in general) about responsibilities in these kinds of situations.
If you make your views too dumb then your model can become too view-sentric (tightly coupled).
IMHO a view can do what it likes but the guiding principle should be: where does it get its information from? If the answer is "the model" then use as much logic as you like.
An "if/else" construct is fine if the view is alternating modes, e.g. formatting a U.S. address vs. a foreign address in an order screen.
However, any logic that you place into a view should not alter the model.
Add this helper to your application_helpers.rb It will surround your links with <li> and <li class="active"> if the link is the current page.
Use it in place of a link_to.
link_to 'home', root_url, optional_condition_argument_goes_here
def active_link_to(text, url, condition = nil)
if condition.nil? and String === url
condition = url == request.path
end
content_tag :li, link_to(text, url), :class => (condition && 'active')
end
(Courtesy of Mislav)
I might put if-else in a view. In most cases not. The real question in my mind is whether the logic could go anywhere else without being messier.
I tend to avoid putting control-flow logic in my views (ASP.NET MVC) except under circumstances where I may want a portion of the interface visible/not visible based on the presence or absence of data. In this case, it is view logic -- I'm determining the layout of the page, the elements of the page that are available, etc. I think that this is perfectly acceptable and preferable to having the controller determine this or multiplying views to account for minor variants. The controller needs to give the view enough information for it to be able to render the view and its variants as needed.
What I wouldn't put into the view is business logic that determines how to calculate something or whether to perform some action (except, perhaps, for role-based decisions -- these seem to crop up just about everywhere). Other than client-side validation, my business logic resides in the controller/model.
An example of where I might use if/then logic in a view is a view which displays events. In my app, events can have subevents, but subevents can't have further subevents: a two level hierarchy. On my display page, I have tabs for Details, Groups, Participants, and Subevents. These are the same for both events and subevents, with the exception of the Subevent tab. It shouldn't exist for a subevent. Rather than repeat myself by having two different views that are virtually identical except for that one tab, I've added a tiny amount of logic to the view to not render the Subevent tab if an event has none.
By the same token, I wouldn't go so far as to have a single "view" that uses logic to determine whether to show an overview or details or editing pane, etc. based on the value of some view data item. This seems an abuse of the single responsibility principle as applied to views. Each view should have a single-purpose, IMO.
Logic that is in the view should not be required to fully describe the current state of the model.
Said another way, logic in the view is acceptable if that logic is used to format or alter the visualization of the information. Logic in the view might also have a use in vetting data that is entered before taking the expense of transmitting that data to the controller (in a client/server or web application).
For instance, the view might include logic to split a list of items into multiple columns when the list is longer than N items. That split could be done in several different ways according to the exact nature of the view (e.g. http, mobile device, pdf, voice reader, Morris Code, etc, etc, ad nasium). The full view information might need to be paginated - and that can only be done in the view. Formatting logic should not ever be included in the controller or the model.
As a corner case, the view might include logic to check that a password entered for a new user meets the current security requirements (e.g. double entry of password matches; at least N characters long; does not include spaces or the "*" character; includes at least three of the following: lower case letters, upper case letters, numbers, symbols; is different than the last N passwords, no based on a dictionary word, etc, etc). Depending on the nature of the logic, vetting a password could be thought of as "formatting" or as "business logic". It might be that the check happens in two passes - one set of checks for formatting in the view, and another set of checks in the controller with info from the model (the last N passwords).

Resources