views:

215

answers:

8

Hi,

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.

A: 

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.

Chuck
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.
A: 

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.

tvanfosson
+2  A: 

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).

Breton
+3  A: 

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.

Emil Ivanov
So, if the logic depends on the view, it is okay?
Yes - then is fine. Also note that whatever logic is in the view it should be ridiculously simple.
Emil Ivanov
+1  A: 

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.

cletus
I think not enough hand-wringing is a much bigger problem, as evidenced by some codebases I've seen. Also, it's usually the controller or a helper into which you put the logic, not the model — at least in the cases I most often come across.
Chuck
A: 

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.

Jen
A: 

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).

semiuseless
+1  A: 

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)

chap