Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
West Wind WebSurge - Rest Client and Http Load Testing for Windows

Odd/Even Looping in ASP.NET MVC


:P
On this page:

Ran into a post from Steve Sandersen earlier in which he laments the verbosity of doing things like odd/even parsing in an iterative loop in ASP.NET MVC. Steve proceeds to show an abstract solution which is a great idea for more complex scenarios, but if all you need is odd even type parsing may be a bit of overkill especially since it such a common scenario.

I tend to use a slightly simpler approach for odd even figuring based on a logical variable that’s changed in a loop. Here’s what my version of similar code looks like:

    <% bool oddEven = true;
       foreach (CodeSnippetListItem snip in snippetList)
       {  %>
       
        <div class="<%= (oddEven = !oddEven) ? "evenclass" : "oddclass" %>">
            Content goes here...
        </div>
    <% } %>

That’s not too bad to read as far as tag soup goes. The key is a logical var that is simple ‘not-ed’ – this can be done after the { or as I’ve done here direclty inline of the expression. The only hard part with this code is figuring out whether it starts on odd or even :-}

Another option is to use some client script code – jQuery can make short work of applying classes after the page’s been loaded.

<script type="text/javascript">
    $(document).ready(function() {
        $(".snippet:odd").addClass("listalternate");
    });    
</script>

Given the two approaches I think the former is the better choice because I like to keep the display at the point where it’s applied in the HTML or style sheet and just in case JavaScript doesn’t work the display is consistent either way.

Options are good though…

Posted in MVC  

The Voices of Reason


 

mottey
August 31, 2009

# re: Odd/Even Looping in ASP.NET MVC

ASP.NET MVC: Avoiding Tag Soup (http://blog.wekeroad.com/blog/asp-net-mvc-avoiding-tag-soup/) showed using extension methods to minimise the mess of things like alt rows:
 <tr class="<%=Html.GetRowClass(rowIndex) %>">
    <td><%=p.Title%></td>
    <td><%=p.Permalink%></td>
</tr>

Having worked on heavy JavaScript/AJAX sites we quickly learnt that the convenience of using jQuery to add alt row classes wasnt worth the (albeit minimal) client-side performance hit.

Rick Strahl
August 31, 2009

# re: Odd/Even Looping in ASP.NET MVC

@mottey - Yeah Rob likes to go overboard with Html Helpers :-}. I think they're useful but overkill for simple things. Certainly in the above I don't think I would create an HTML helper but if anything add that to a custom ViewModel with a method that handles this. Helpers to me are generic and apply globally, but I suppose you can create them into a custom namespace specific for the View/Controller/Page so it's only visible there. Otherwise you have some nasty extension method namespace collisions.

This approach (GetRowClass that explicitly hardcodes the class names for odd and even) takes a view feature - the CSS class name - and puts it in code which to me is all wrong. The view should be changeable by a designer without having to look into a separate code file.

While I'm no big fan of tag soup I think many folks are overreacting to keeping the view clean of code. By removing display elements and even display logic out of the view into helpers or other support methods you're actually making the flow of the page harder to read, understand and most importantly modify.

9eFish
August 31, 2009

# Odd/Even Looping in ASP.NET MVC - Rick Strahl's Web Log

9efish.感谢你的文章 - Trackback from 9eFish

Rob Conery
August 31, 2009

# re: Odd/Even Looping in ASP.NET MVC

BARF! :)

Overboard? Funny when I read this I fired up LiveWriter and started to write "Why Rick Needs a Helper Enema" but then thought to myself - wait a minute, I've written this stuff before and found the post that mottey referenced.

So Rick - I love you man but listen, you need to "get into the groove" a bit before dissing me :). In this case, there are many helpers that you can use/reuse and encapsulate. This kind of thing:

<%= (oddEven = !oddEven) ? "evenclass" : "oddclass" %>

Is just not cool my man. The whole idea of DRY is that you don't want that exact thing all over your views (it's repetitious, crunchy, and if you change your mind... well you get it).

Helpers terse-up the View and make "slinging" the HTML/View logic easier. You used to give me a hard time about the lack of components - well this kind of thing underscores that pain. Some discipline here will help you - I promise!

Rick Strahl
August 31, 2009

# re: Odd/Even Looping in ASP.NET MVC

@Rob - we'll have to disagree on that. Putting a CSS classname inside of code doesn't terse up anything - all you're doing is moving your view logic out of the view into code where it doesn't belong. Besides being wrong conceptually - it's more code to debug and test,

Next you're going to tell me you don't like <%= Bite.Me %> as an expression either, huh?:-}

Danyal
September 01, 2009

# re: Odd/Even Looping in ASP.NET MVC

NVelocity is good for this stuff:

#foreach(...)
  #beforeall
    ...
  #afterall
    ...
  #odd
    ...
  #even
    ...
  #nodata
    ...
  #each
    ...
#end

Ryan Roberts
September 01, 2009

# re: Odd/Even Looping in ASP.NET MVC

The spark syntax for this sort of thing is a ..little bit cleaner.

<div each="var snip in snippetList" class="oddclass?{snipIndex % 2 == 0} evenclass?{snipIndex % 2 != 0}">
  Content goes here
</div>


And you can push it into a parametrised partial if you want reuse to make Rob happy. Cut the markup out, rename the collection to something suitably generic, name the partial _AlternatingDivs and you can call it using:
<AlternatingDivs items="snippetList"/>


Look ma, no HtmlHelpers. Spark partials and macros eliminate much of the need for them.

David Robbins
September 01, 2009

# re: Odd/Even Looping in ASP.NET MVC

For ease of maintenance I would go with the jQuery option as you have more flexibility with maintenance. Rob did say embrace your inner-scripter ;)

Neil Kerkin
September 01, 2009

# re: Odd/Even Looping in ASP.NET MVC

Who's Scott Sanderson? :P

How much friction is created when css class names change? Probably not something that happens that often but someone will have to touch all the <%= (oddEven = !oddEven) ? "evenclass" : "oddclass" %> throughout a project.

How would you handle First, Last, Interior, etc?

Maybe a better solution would be to overload Steve's CssClass(string prefix){...} with
CssClass(string even, string odd){...} and
CssClass(string even, string odd, string first, string last, string interior){...}

Not as scalable but still allows the css class names to be defined within the view.

Ryan Roberts
September 01, 2009

# re: Odd/Even Looping in ASP.NET MVC

>How would you handle First, Last, Interior, etc

More Spark advertising. Spark iteration defines variables IsFirst,isLast,Index and Count. So you can do:

<div each="item in collection" class="first?{itemIsFirst} last?{itemIsLast}">
Item ${itemIndex} of ${itemCount}
</div>


It's almost like the guys who work on it do web programming for a living.

Rick Strahl
September 01, 2009

# re: Odd/Even Looping in ASP.NET MVC

@Neil - re: changing classes: You'd have that issue in plain markup as well, so using code doesn't change much in that respect and you could still do a search and replace the same way you'd do in markup I suppose.

I guess I'm stuck in my ways but personally I don't see the need to create an alternate syntax for views when all these alternate syntaxes are doing is approximating the code anyway in a different and non-familiar way. To me this smells of another layer of abstraction and another 'language' you have to learn and track and maintain (and new developers) - to me this feels like more hassle than it's worth. Given everything code is the most flexible way to do anything you need even if it might be more verbose.

Sometimes it really feels to me that people take form over function a bit to far (memories of discussion with Rob re: REST formatting comes to mind too) :-}

Neil Kerkin
September 01, 2009

# re: Odd/Even Looping in ASP.NET MVC

@Rick, agree with changing class names. I guess I'm more concerned about having the same logic to select classes repeated across various views. And yes, it is *view* logic, but not quite so easy to do find and replace on, especially when dealing with more than just odd/even.

We're abstracting away a lot of html with helpers already so it kinda seems like a natural progression.

Rick Strahl
September 01, 2009

# re: Odd/Even Looping in ASP.NET MVC

@Neil - understood and in general I agree with the HtmlHelper concept. But to me that's better left to generic tasks, that are globally applicable. Application specific stuff IMHO doesn't belong in helpers but a custom ViewModel with helper methods there that handles this.

Then again this is just my gut feeling and for all I know is this may be completely off base, but I'm against abstracting too much logic into little tiny morsels that you have to hunt down all over the place in code. To be honest I've not had enough time with MVC at this point to make any judgement calls even for my own code let alone for making suggestions to others :-}.

AC
September 01, 2009

# re: Odd/Even Looping in ASP.NET MVC

I'm going to side with Rick on this one. The view is responsible for the markup, and who says it's always the same alternate class in every view?

I don't see any utility in replacing 1 line of simple code with a helper. It's adding unnecessary coupling and polluting the rest of the code.

But, uf you're going to go mad and code one anyways, instead of a static helper, at least create a simple class that does it for you.

e.g.
    <% var altRow = new AltRow("oddclass", "evenclass");
       foreach (CodeSnippetListItem snip in snippetList)
       {  %>
       
        <div class="<%= altRow.Row() %>">
            Content goes here...
        </div>
    <% } %>


and the AltRow is trivially easy, but at least the state and behavior is refactored away, and also doesn't depend on an index. I think many people missed the fact that Rick wasn't iterating using a for loop.

class AltRow
{
   private string oddClass;
   private string evenClass
   private bool isOdd = false;

   public AltRow(string oddClass, string evenClass)
   { ... }

   public string Row()
   {
      isOdd = !isOdd;
      return isOdd ? oddClass : evenClass;
   }
}

Rick Strahl
September 02, 2009

# re: Odd/Even Looping in ASP.NET MVC

@AC - I like it! That actually makes a lot more sense than a specific helper.

Benjamín Eidelman
January 26, 2010

# re: Odd/Even Looping in ASP.NET MVC

I liked most the last approach (by AC) (I don't like much the naming of class and methods, but that's not the point)

I would prefer a:
public class Alternator<T> {
   public Alternator(T odd, T even);
   public T Next();
}

That would allow me alternate any other values on my templates.

Anyway, I don't find much sense in the "and if you change your mind..." Rob comment, really, how often would you change your mind about this expression:
<%= (oddEven = !oddEven) ? "evenclass" : "oddclass" %>

it's just an "odd/even" snippet.

by the way, Rick, is there code colouring for this Asp.Net with includes?

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024