Code Based Repeater for ASP.NET MVC

asp.net, asp.net mvc, code 0 comments suggest edit

Not long ago, my compadre Scott Hanselman related the following story

In a recent MVC design meeting someone said something like “we’ll need a Repeater control” and a powerful and very technical boss-type said:

“We’ve got a repeater control, it’s called a foreach loop.”

I beg to differ. I think we can do better than a foreach loop. A foreach loop doesn’t help you handle alternating items, for example. My response to this story is, “The foreach loop is not our repeater control. Our repeater control is an iterating extension method with lambdas!”. Because who doesn’t love lambdas?

Not many people realize that within an ASPX template, it’s possible to pass sections of the template into a lambda. Here, let me show you the end result of using my Repeater<T> helper method. It’s an extension method of the HtmlHelper class in ASP.NET MVC.

<table>
  <% Html.Repeater<Hobby>("Hobbies", hobby => { %>
  <tr class="row">
    <td><%= hobby.Title %></td>
  </tr>
  <% }, hobbyAlt => { %>
  <tr class="alt-row">
    <td><%= hobbyAlt.Title %></td>
    </tr>
  <% }); %>
</table>

This renders a table with alternating rows. The Repeater method takes in two lambdas, one which represents the item template, and another that represents the alternating item template.

This particular overload of the Repeater method takes in a key to the ViewData dictionary and casts that to an IEnumerable<T>. In this case, it tries to cast ViewData["Hobbies"] to IEnumerable<Hobby>. I’ve included overloads that allow you to explicitly specify the items to repeat over.

This isn’t very remarkable when you think a bout it. What the above template code translates to is the following (roughly speaking)…

Response.Write("<table>");

Html.Repeater<Hobby>("Hobbies", hobby => {
    Response.Write("  <tr class=\"row\">");
    Response.Write("    <td>");
    Response.Write(hobby.Title);
    Response.Write("    </td>");
    Response.Write("  </tr>");
  }, hobbyAlt => { 
    Response.Write("  <tr class=\"alt-row\">");
    Response.Write("    <td>");
    Response.Write(hobbyAlt.Title);
    Response.Write("    </td>");
    Response.Write("  </tr>");
  });

Response.Write("</table>");

The code for the Repeater method is simple, short, and sweet.

public static void Repeater<T>(this HtmlHelper html
  , IEnumerable<T> items
  , Action<T> render
  , Action<T> renderAlt)
{
  if (items == null)
    return;

  int i = 0;
  items.ForEach(item => {
    if(i++ % 2 == 0 ) 
      render(item);
    else
      renderAlt(item); 
  });
}

public static void Repeater<T>(this HtmlHelper html
  , Action<T> render
  , Action<T> renderAlt)
{
  var items = html.ViewContext.ViewData as IEnumerable<T>;
  html.Repeater(items, render, renderAlt);
}

public static void Repeater<T>(this HtmlHelper html
  , string viewDataKey
  , Action<T> render
  , Action<T> renderAlt)
{
  var items = html.ViewContext.ViewData as IEnumerable<T>;
  var viewData = html.ViewContext.ViewData as IDictionary<string,object>;
  if (viewData != null)
  {
    items = viewData[viewDataKey] as IEnumerable<T>;
  }
  else
  {
    items = new ViewData(viewData)[viewDataKey] as IEnumerable<T>;
  }
  html.Repeater(items, render, renderAlt);
}

Some of the ViewData machinations you see here is due to the fact that ViewData might be a dictionary, or it might be an unknown type, in which case we perform the equivalent of a DataBinder.Eval call on it using the supplied view data key.

It turns out that the regular <asp:Repeater /> control works just fine with ASP.NET MVC, so there’s no need for such an ugly method call. I just thought it was fun to try out and provides an alternative approach that doesn’t require databinding.

UPDATE: I wanted to end this post here, but my compadre and others took exception to my implementation. Read on to see my improvement…

As astute readers of my blog noted, the example I used forces me to repeat a lot of template code in the alternative item case. The point of this post was on how to mimic the repeater, not in building a better one. Maybe you want to have a completely different layout in the alternate item case. I was going to build a another one that relied only on one template, but I figured I would leave that to the reader. But noooo, you had to complain. ;)

So the following is an example of a repeater method that follows the most common pattern in an alternating repeater. In this common case, you generally want to simply change the CSS class and nothing else. So with these overloads, you specify two CSS classes - one for items and one for alternating items. Here’s an example of usage.

<table>
  <% Html.Repeater<Hobby>("Hobbies", "row", "row-alt", (hobby, css) => { %>
  <tr class="<%= css %>">
    <td><%= hobby.Title%></td>
  </tr>
  <% }); %>
</table>

And here’s the source for the extra overloads. Note that I refactored the code for getting the enumerable from the ViewData into its own method.

public static void Repeater<T>(this HtmlHelper html
  , IEnumerable<T> items
  , string className
  , string classNameAlt
  , Action<T, string> render)
{
  if (items == null)
    return;

  int i = 0;
  items.ForEach(item =>
  {
    render(item, (i++ % 2 == 0) ? className: classNameAlt
  });
}

public static void Repeater<T>(this HtmlHelper html
  , string viewDataKey
  , string cssClass
  , string altCssClass
  , Action<T, string> render)
{
  var items = GetViewDataAsEnumerable<T>(html, viewDataKey);

  int i = 0;
  items.ForEach(item =>
  {
    render(item, (i++ % 2 == 0) ? cssClass : altCssClass);
  });
}

static IEnumerable<T> GetViewDataAsEnumerable<T>(HtmlHelper html, string viewDataKey)
{
  var items = html.ViewContext.ViewData as IEnumerable<T>;
  var viewData = html.ViewContext.ViewData as IDictionary<string, object>;
  if (viewData != null)
  {
    items = viewData[viewDataKey] as IEnumerable<T>;
  }
  else
  {
    items = new ViewData(viewData)[viewDataKey] 
      as IEnumerable<T>;
  }
  return items;
}

Hopefully that gets some people off my back now. ;)

Technorati Tags: aspnetmvc,asp.net

Found a typo or error? Suggest an edit! If accepted, your contribution is listed automatically here.

Comments

avatar

63 responses

  1. Avatar for Scott Watermasysk
    Scott Watermasysk May 3rd, 2008

    Or just use NVelocity which has really nice support for alternating rows (and much more) built in.
    http://www.castleproject.or... (see fancy foreach loops).
    I have not used much NVelocity yet for MVC, but we use it through out Graffiti and it is a joy to use (especially if you hate the constant context jumping required for aspx's.

  2. Avatar for Scott Hanselman
    Scott Hanselman May 3rd, 2008

    I respectfully disagree. ;) IMHO, it's widely agreed that using server-generaed alternate CSS classes for alternating rows is a sub-optimial thing. In my opinion, the View is the view, sure, but the *skinning* of the view should be as much on the client/css as possible. Alternating rows are a client-side presentation detail that the server shouldn't be sweating.
    I'd prefer doing it like this in jquery, without any trouble on the server-side:
    $(document).ready(function() {
    $('table.striped tbody tr:not([th]):odd').addClass('odd');
    $('table.striped tbody tr:not([th]):even').addClass('even');
    });
    Additionally, that server-side repeater doesn't handle triple striping, grouped striping, alternating triplets, etc.
    Just my 2 bytes.
    See this page for more details.

  3. Avatar for VIjay Santhanam
    VIjay Santhanam May 3rd, 2008

    Wikid! That's cool!

  4. Avatar for Peli
    Peli May 3rd, 2008

    2 more bytes: instead of putting logic to alternate the css class, you force the user to duplicate the entire row generation. that's a lot of duplication.

  5. Avatar for Haacked
    Haacked May 3rd, 2008

    @peli, @hanselman well this is a simple example. Suppose I wanted a totally different layout for alternating items.
    I was going to write yet another overload that makes doing the alternate CSS class without repeating the template simpler too, but figured I'd leave that as an exercise to the reader.

  6. Avatar for Jonathan Carter
    Jonathan Carter May 3rd, 2008

    The thinking behind this is pretty cool. While that dual-lambda is a little cryptic (subjectively), it does illustrate how creative you could get with MVC.

  7. Avatar for Haacked
    Haacked May 3rd, 2008

    Ok, I updated my post to show yet another approach.

  8. Avatar for SAprelov
    SAprelov May 3rd, 2008

    I guess "view" must be in "view":)
    jQuery rules:
    CSS:
    table tr:nth-child(odd)
    {
    background-color: magenta;
    }
    Code:
    $("tr:nth-child(odd)").addClass("odd");

  9. Avatar for Steve
    Steve May 3rd, 2008

    We have a repeater...it's called a repeater :)
    I use the repeater in my ms mvc apps with jQuery sorting and paging.

  10. Avatar for Tuna Toksoz
    Tuna Toksoz May 3rd, 2008

    Why don't we put this into a ComponentController? Isn't it better?

  11. Avatar for Steve
    Steve May 3rd, 2008

    Here is sample of what I am talking about:
    http://blogger.forgottenski...
    Granted, to have a helper is a great idea, I'm just showing that we 'have a repeater' and it support templating of course - I just show the itemtemplate.

  12. Avatar for Steve
    Steve May 3rd, 2008

    oh, you did come back and address what I was talking about :)
    sorry about that - on the bright side, maybe that quick example I cooked up will help someone else - lol
    All I can say is this ASP.NET MVC has been incredible to work with, especially using jQuery. I am using the ajax form, validation, other aspects and the best part: full control over everything :)
    I've bounced back and forth over using a foreach or a repeater. The repeater handles null bindings better, I don't like needing to do < % if(... == null) { % > etc... that is ugly stuff.

  13. Avatar for Scott
    Scott May 4th, 2008

    For the second example I would probably just wrap it in a for loop and output my rows like so.
    <tr class="<%=(rowNum%2==0)?"evenCssRow":"oddCssRow";%>">
    I think if you keep refactoring the repeater helper to account for all cases, you'll end up writing the repeater control. ;)

  14. Avatar for Mischa Kroon
    Mischa Kroon May 4th, 2008

    I don't really like this way of doing things.
    Scott's example seems both cleaner, takes less code and is less complex.
    ForEach + Jquery / other framework CSS insertions for the win :)

  15. Avatar for Michael Teper
    Michael Teper May 4th, 2008

    I like the jQuery examples simply because they don't involve the hideous spaghetti code that is quickly becoming the distinguishing feature of all the MVC examples I am seeing, and is touted as a good thing to boot. Its not. Whatever its shortcomings, ASP.NET gave us a way to code cleanly (compared to classic ASP, for example), so lets not throw the baby out with the bathwater.

  16. Avatar for Scott Hanselman
    Scott Hanselman May 4th, 2008

    Ya, if a repeater works maybe use that for nulls and JQuery for the rest.

  17. Avatar for Chris Chandler
    Chris Chandler May 4th, 2008

    Thanks for the update, reading your post, I was hoping you would refine it to use a css switch, kudos.
    Must say, since mvc is all about separation of concerns, alternating rows is a style issue. Since I'm the ultimate jQuery fanboy anyway, jQuery FTW.
    Lambdas are nice here. But why all the ceremony about a loop? Seems like an awful lot of moving pieces just to iterate some tr's?

  18. Avatar for Lou D
    Lou D May 4th, 2008

    Cool trick! Quite a picky audience. Sounds like it could be an interesting way to get stuff other than html-encoded text in a link.
    public static void ActionLink<T>(
    this HtmlHelper html,
    Expression<Action<T>> action,
    Action linkContents) where T:Controller
    {
    string url = LinkBuilder.BuildUrlFromExpression(
    html.ViewContext, action);
    html.ViewContext.HttpContext.Response.Write(
    string.Format("<a href=\"{0}\">", url));

    linkContents();

    html.ViewContext.HttpContext.Response.Write("");
    }
    in aspx
    <% var x = "foo"; %>

    <% Html.ActionLink<HomeController>(
    home => home.About(),
    () => {%><span class="<%=x%>">hello</span><%});
    %>


  19. Avatar for Rob Conery
    Rob Conery May 4th, 2008

    "We’ve got a repeater control, it’s called a foreach loop."
    That was me pinhead :).
    Dig the lambda/template bits. You've got my mad scientist juices flowing...

  20. Avatar for James Gregory
    James Gregory May 4th, 2008

    Overkill? Obtuse certainly.
    I agree with Scott H that it's probably all unnecessary, leave it to javascript; however, if you really want to do it, why is the mvc implementation better than simply using an if statement?
    Why is this better than:
    <% foreach ... {
    if IsAlt { %>
    ...
    <% } else { %>
    ...
    <% }
    } %>
    MVC seems to be forgetting to KISS...

  21. Avatar for Joe Brinkman
    Joe Brinkman May 4th, 2008

    I love it. Something as simple as a reapeater and we have 30 different methods to achieve the same thing. Definitely what I want my devs spending their time working on. I guess spending time on solving actual business problems is so yesterday, now devs will get to spend time learning how to rebuild basic server controls.

  22. Avatar for Chris Chandler
    Chris Chandler May 4th, 2008

    @joe - Spending your time monkeying with someone else's contrived Html, is so yesterday. Taking control and making it look exact with your designer, so now.

  23. Avatar for Haacked
    Haacked May 4th, 2008

    @Joe because every problem in computer science and software engineering has been solved, so no point in trying to experiment with different ways of doing anything, right? ;)
    It's a matter of choice and preference. It's why you guys (DNN) stuck with VB, while many devs stuck with C#. We have 30 different languages to solve things, but that's a good thing, right?

  24. Avatar for Sameer
    Sameer May 4th, 2008

    Do people you work with say, "watch what you say, it might end up on Phil's blog"?
    :D
    guys... watch your back (just kidding)

  25. Avatar for Jason Simone
    Jason Simone May 5th, 2008

    Scott,
    Why would you want your view to be dependent on client-side script - especially when it doesn't need to be? You say it's widely agreed that this is best practice so I'm really curious to see why. To me that defeats the whole idea of keeping your View nice and straightforward.
    Working for government, our paranoid techs distribute a lot of PCs with JavaScript turned off so it is of particular concern to me to choose where I use it wisely. I would never mix the initial presentation state of my page with client-script if I can easily avoid it. But perhaps I also just have a fear of mixing too much into client-script because I still find it much more difficult to organize than views in a nice MVC site.

  26. Avatar for Stephen
    Stephen May 5th, 2008

    I can't quite believe it was recommended to use jquery to style the page instead..
    Thats just.. really scary

  27. Avatar for Stephen
    Stephen May 5th, 2008

    I'm wondering, while I've started to get more love for the helper method way of generating html..
    I wonder if theres any thought to upgrade the control system for asp.net, something more like wpf binding.. I know webforms provides a control system, and that can even be used within the mvc, but personally i don't think they reflect the mvc well, and I fear the helper methods are really going backwards.. in terms of:
    Monolithic helpers for various different amounts of overloads you require..
    Compared to the controls system of webforms, where you compose an instance that will eventually render.. not the mension that data the forms forms controls actually look like what you are doing vs tons of <% %> <%= %> yadda yaddas..
    As someone who spent a lot of time with ASP, it seems all too familiar, I'm wondering if you guys who aim to retire controls in favour of tons of methods have ever used asp? :P

  28. Avatar for Haacked
    Haacked May 5th, 2008

    @Stephen we do have intentions to look into MVC specific declarative controls, but not necessarily for MVC 1.0. I think we want to get the core framework done first and make sure code based approaches work first.

  29. Avatar for Scott Hanselman
    Scott Hanselman May 5th, 2008

    Seems to me that the current web would be crippled with Javascript disabled. I thought that the great Javascript/Cookies scare of 1998 was over. ;)

  30. Avatar for mario
    mario May 5th, 2008

    we're back to spaghetti ASP except now in MVC. the trivial asp.net mvc examples are barely tolerable going in and out of <% %>. have you ever considered adding first-tier support for templates?
    <mvc:repeater-template id="MyTable">
    <layout>
    <table>
    <tr><th>Name</th></tr>
    <mvc:render-item />
    <table>
    </layout>
    <item>
    <mvc:render-template id="even" when="row => row.IsEven" />
    <mvc:render-template id="odd" when="row => row.IsOdd" />
    </item>

    <empty>
    </empty>
    </mvc:repeater-template>

    <mvc:template id="odd">
    <tr class="odd"><td><%# model.Name %></td></tr>
    </mvc:template>
    <mvc:template id="even">
    <tr class="odd"><td><%# model.Name %></td></tr>
    </mvc:template>

    <html>
    <body>
    <%= Mvc.InvokeTemplate("myTable", ViewData["model"]) %>
    </body>
    </html>

  31. Avatar for jbogard
    jbogard May 5th, 2008

    I hate to say it, but all the C# noise is making me want VBScript back. All the <% %> <%= %> () => {} stuff is pretty noisy. Clever, but noisy.

  32. Avatar for Steven Harman
    Steven Harman May 5th, 2008

    @mario, Don't forget that much of the spaghetti from the old ASP days was about mixing many concerns together into a big, messy, opaque ball of... well of spaghetti. The idea of adapting a pattern like MVC for the web is to help developers fall into the pit of success by making doing the right thing, keeping those concerns separated and in their own space, is the easy thing to do.
    So while I'd agree with several other commenters that this might not be the best use of lambdas and is probably too much ceremony for a simple looping construct, its still all presentation logic. And as such, keeping it in the View is perfectly valid.
    Btw... I'm on board with the idea of having a strong templating engine. Have you looked at how rhtml, NVelocity, or Brail do things?

  33. Avatar for Joe Brinkman
    Joe Brinkman May 5th, 2008

    Phil - My biggest pain point is that in many ways the MVC framework seems to be a huge step backward. One of the greatest advances that I have seen in software development over the last 20 years has been the realization of some of the benefits of code re-use. More specifically, software components and the binary packaging which allows for them to be easily distributed and re-used has resulted in a huge productivity boosts for the development community. This is definitely the case in the desktop world, and to a large degree, it has been that way in the Asp.Net world as well.
    In many ways this feels like the old debate between the VB and C++ crowds... C++ Guy - Look how much control we have over all aspects of our software. We can build anything we want to. VB Guy - Yeah but look at how many real world business problems we have solved while you are still trying to build one simple dialog box.

  34. Avatar for mario
    mario May 5th, 2008

    @steven if a DESIGNER cannot figure out the presentation logic, even if it is acceptable to have it there, then there's too much logic in the UI. nvelocity and brail have for loops, thus i would rather stick with C#.
    a neat approach would be templates + CSS3 selectors on the enumerator. from my previous example, the mvc:repeater would use the odd row template for the item like this:
    <mvc:render-template id="odd" when="nth-child(odd)" />

  35. Avatar for Janko
    Janko May 5th, 2008

    I disagree. You can create a server code and strip html markup using jQuery in a line of code.

  36. Avatar for Richard Bushnell
    Richard Bushnell May 5th, 2008

    While I do like the control afforded by the demo, I have to agree with Joe. The comments to this post demonstrate the point that we are spending too much time worrying about more than one way of doing things.
    In Python, the community really tries to just have one way to do something. In Rails, DHH tells everyone to make their own framework if they want to do it more than one way. We seem to have 20 ways just to do rendering. Ever heard of the anti-pattern, "Design by committee?"
    At the same time, I'm struggling to get ASP.Net to do what I want because there is so much stuff missing or badly designed. I fail to see why we don't learn by experience and have great hackers like you guys spend time getting that right.
    How can we expect anyone to take this up anyway? You guys might be hacks, but I am still trying to train normal developers how to use generics. Lambdas are way beyond them at the moment. And now we're asking them to start learning JQuery, just to do something which they could previously do using a DataGrid?
    In any case, the Rails way is way simpler. They have a class just for cycling through CSS names on each iteration. What about trying something similar to that?

  37. Avatar for Stephen
    Stephen May 6th, 2008

    Hi Scott,
    While js is much more common these days, that shouldn't mean you change menial design choices into using js.. the jquery example just really looked like it was there for the sake of it..
    I'm sure what you are saying is you love the expressive context something like jquery adds.. but I think the inspiration should be to try and make the server side as expressive as css.. the functional side I think we're getting there with c# anyway.. lambdas fill a big gap in, in that respect.

  38. Avatar for Louis DeJardin
    Louis DeJardin May 6th, 2008

    @mario, @bogard: agreed a hundred percent that the road to hell is paved with <%x { %><d t="<%=h.e<y>(y=>y.n)%>" /> <% } %>. Especially with the default editor constantly attempting to realign any order you try to bring to the file.
    But how can you avoid that if you're in the aspx view engine? Myself, I've a fan of nvelocity - I'd love to see a form of '#' and '$' escaping in aspx in addition to <% %> and <%= %>.
    http://www.castleproject.or...

    #foreach($hobby in $Hobbies)
    #beforeall
    <table>
    #odd
    <tr class="row">
    #even
    <tr class="row-alt">
    #each
    <td>$hobby.Title</td>
    #after
    </tr>
    #afterall
    </table>
    #nodata
    <div>You need some hobbies</div>
    #end

    @bushnell agreed about the value of simplicity and providing a clear best practice. Hopefully the net result of this conversation is less about listing 20 different techniques as it is about which is the simplest effective approach.

  39. Avatar for Peter
    Peter May 6th, 2008

    Arrr, all these <%..%> are sooo ugly... It's noise, they get in the way. That NVelocity example is not much prettier either. We need to think about it backwards. Forget what the current design view engine can or cannot do and let's start from scratch. What would we like?

  40. Avatar for Lou D
    Lou D May 6th, 2008

    What if the few things you needed in a view language fit into the html seamlessly?
    (crossing fingers about formatting)
    <var i="0"/>
    <var css="new string[] {'row', 'row-alt'}"/>
    <table>
    <for each="var hobby in Hobbies" i="i+1">
    <tr class="$css[i%2];">
    <td>$i;</td>
    <td>$hobby.Title;</td>
    <td>$Html.Function("arg","arg");</td>
    </tr>
    </for>
    </table>

  41. Avatar for Joey
    Joey May 6th, 2008

    @ScottHa


    Alternating rows are a client-side presentation detail that the server shouldn't be sweating.


    I love JavaScript and use jQuery as my toolkit of choice ... but think 100+ rows your code has to parse and add a simple CSS.
    Compiled FTW.
    Not a knock on jquery ... but I've seen it abused and people stuff their "document.ready" with too much logic that hangs the browser. Be pragmatic.

  42. Avatar for Stephen
    Stephen May 6th, 2008

    I'm not sure what any of these alternatives provide other than a different way to make spaghetti..
    I don't see whats so wrong with server side controls.. wpf and xaml work great.
    asp.net just needs some cleaner binding.. generics aware if possible.
    Not that I like the current server side controls, they are far too tied to the webforms paradigm for me to feel comfortable with..

  43. Avatar for JontyMC
    JontyMC May 23rd, 2008

    How come your IEnumerable<T> has a ForEach method on it?

  44. Avatar for Haacked
    Haacked May 23rd, 2008

    @JontyMC I wrote my own ForEach extension method for it. :)

  45. Avatar for Miguel de Icaza
    Miguel de Icaza May 27th, 2008

    Except the problem with your generic/lambda-aware repeater is that it took me a while to figure out what that code did, simple beats clever.

  46. Avatar for Tuna Toksoz
    Tuna Toksoz June 19th, 2008

    Is the lambda-in-aspx stuff(the repeater template) bound to current HttpContext, i mean what if I store the delegate in session and invoke it in another request? Will it run against the new HttpContext or the old one?

  47. Avatar for mgutz
    mgutz July 4th, 2008
  48. Avatar for Barry
    Barry July 25th, 2008

    ARen't you in danger of thinking MVC is a screwdriver, when it's really just a hammer? I thought the whole point of MVC was to completely seperate view issues from the model. Surely JQuery is the answer here, otherwise you're going back to mixing display matters in with business stuff? I find this whole thread confusing now, having been discussing with my team switching to MVC in order to separate presentation from business. Perhaps someone can tell me what I've missed?

  49. Avatar for Budigelli
    Budigelli July 25th, 2008

    I may be on the wrong foot here...But i like JQuery.
    I would let my jquery take care of the UI issues compared to the server side processing to certain extent.
    For template engine - JQuery "Superfly DOM"
    Styling - simple few lines would give much control over the display alternative items, grouping etc with Jquery and CSS.
    What ever makes my job easier to develop and maintain (and things in between)!

  50. Avatar for StackOverflow
    StackOverflow November 22nd, 2008

    I am thinking, howto implement the same thing, in control! Like this:


    Page.aspx
    <Content>
    // some where in the body
    <% Html.PartialView("Tpl.ascx")
    </Content>
    Tpl.ascx
    <div>Some tags</div>
    <% Head(() => { %>
    and this part goes to head tag
    <% } %>


  51. Avatar for Todd Smith
    Todd Smith December 6th, 2008

    @Barry these type of helper methods are only used by the view engine. The model and controller are oblivious to them.

  52. Avatar for Mikem
    Mikem March 5th, 2010

    I must say I'm somewhat shocked that someone as respected as Scott Hansalman would suggest that alternating row styles should be handled in client side javascript.
    Alternating row styles are very much the concern of the view, by definition, which is exactly where it is going (the ASPX file). What about all the other classes you set in the view? Do you have a giant block of javascript that gets every individual element by id and puts a class on it? Of course not! It is perfectly acceptable to have the VIEW set what css classes each element should have.

  53. Avatar for Tim
    Tim March 28th, 2010

    Scott H -- the jquery example might be strictly in the view, but that won't support noscript scenarios.

  54. Avatar for Jay S
    Jay S September 2nd, 2010

    Delegating styling to JQ is retrograde. It is suboptimal in the context of maintainability if it is a particularly large project. Basically we have part of the styling happening in the server-side view and partly in the client-side JQ.

  55. Avatar for guest
    guest November 13th, 2010

    does this repeater works with razor view engine?

  56. Avatar for Webslinger
    Webslinger December 30th, 2010

    I get 'System.Collections.Generic.IEnumerable<T>' does not contain a definition for 'ForEach'
    My project was in 3.5, now upgraded to 4.0, but I get the same error.
    Also, I had to change "items = new ViewData"
    to "items = new ViewDataDictionary"

  57. Avatar for John
    John January 29th, 2011

    Is this even possible using razor view engine? If so, anyone get it to work in razor?

  58. Avatar for Sean
    Sean February 9th, 2011

    Same question as a couple other people, is this helper usable with the Razor engine? I've been having problems w/ the syntax of it if it is. If not is it possible to make a declarative helper in Razor where you pass it a generic list and the html code it will repeat?
    Thanks,
    Sean

  59. Avatar for Hvm
    Hvm August 3rd, 2011

    Hi,
    i m new in in MVC
    I want to use this functionality in my application but so many error occur.
    Please provide me sample of this blog via mail.
    Thanks,
    hvm

  60. Avatar for Parminder
    Parminder September 12th, 2011

    Haached,
    Thanks for the article.
    Where is this ForEach. I cant find it.
    Regards
    Parminder

  61. Avatar for Travis
    Travis November 1st, 2011

    @Everyone looking for the ForEach (extension) method. If you took the time to read *all* Phil's comments above, you would see that he rolled his own ForEach extension method.

  62. Avatar for Saeed Neamati
    Saeed Neamati December 7th, 2011

    Wow! I love what Scott has proposed. This way, we only loop over items (without bothering to find alternating rows and adding a different class to them), then in client-side, we find those rows easily using jQuery. That rocks man! I love you Haccked. This post saved me from hours of vain search.

  63. Avatar for Zain
    Zain April 27th, 2012

    hello everyone,
    is there anyway by which i can have alternating columns color change in repeater?