tags:

views:

113

answers:

4

I need to render a list of Person objects, say, in a comma delimited format using a Partial View in ASP.NET MVC. My problem is that when rendered using the following code:

<% foreach (var person in Model) { %>
    <%= Html.ActionLink<PersonController>(c => c.Edit(person.PersonID), Html.Encode(person.Name)) %>,&nbsp;
<% } %>

I get a trailing comma after the last item. What's the most elegant/least stupid way to have this list of persons rendered without the last comma?

My two options so far, in no order, would be:

  1. Use JavaScript to remove the trailing comma on the client side
  2. Manually create the list using code, instead of markup, in the partial view

Neither of these options appeal to me - any ideas?

Thanks!

+2  A: 
<% bool first = true;
   foreach (var person in Model) { 
     if (first) first = false; else Response.Write(","); %>
     <%= Html.ActionLink<PersonController>(c => c.Edit(person.PersonID), Html.Encode(person.Name)) %>
<% } %>
Mehrdad Afshari
You've got the right idea, but I think your logic is wrong. This will write out on comma at the beginning only.
Robert Harvey
@Robert: Oooops. Thanks for pointing that out. It felt wrong to me but I couldn't notice it. Seems like I should get some sleep ;)
Mehrdad Afshari
+1 That will work.
Robert Harvey
I absolutely did not consider using a Response.Write inside the code block. Thanks Mehrdad.
Ryan Shripat
Indeed, Response.Write and <%= %> are equivalent. You can swap one with the other easily. Here it was a simple comma so I decided to leave it as Response.Write. For more complex delimiters, it makes sense to use the other method.
Mehrdad Afshari
+2  A: 

How about:

<%=String.Join(
    ",",
    Model.Select(
        person=>
            Html
            .ActionLink<PersonController>(
                c => c.Edit(person.PersonID), 
                Html.Encode(person.Name)
            )
    )
    .ToArray()
)%>

(untested)

spender
While I endorse this solution in code files, it usually looks crappy when embedded in markup, and it's less efficient.
Mehrdad Afshari
all code+markup looks crappy! Tags in loops look fairly messy to me.
spender
Elegant, and close, but what is the .ToArray() for? Will it render to the web page?
Robert Harvey
String.Join takes an array of string as the second param. ToArray converts IEnumerable<string> to string[] as required by the Join API
spender
As ActionLink returns a string, this should be fine. Try the code in a webpage. Should work as a substitute to your code... I think
spender
OK, I get it. String.Join joins the array created by ToArray() back to a string.
Robert Harvey
+1  A: 

I think, instead of a foreach, you're going to have to iterate through the persons collection using a conventional for loop. That way, you can detect the last iteration through the loop and avoid the last comma.

<% { int count=Model.Persons.Count();
     for (int i=0; i< count; i++) { %>
     <%= Html.ActionLink<PersonController>(c => c.Edit(Persons[i].PersonID), Html.Encode(Persons[i].Name)) %>
     <% if (i < count) { Response.Write(","); } 
   } %>
Robert Harvey
You can't do that efficiently if your model is IEnumerable<T> rather than IList<T>.
Mehrdad Afshari
+1 for clarity....
Ryan Shripat
@Mehrdad - interesting - could you elaborate?
Ryan Shripat
Under the hood, a foreach enumeration does the same thing. The for loop might even be slightly faster, since it does not have to go through an iEnumerable and yield statement.
Robert Harvey
IEnumerable has no efficient Count() method. Counting requires enumeration.
spender
Well, I like Mehrdad's solution better anyway.
Robert Harvey
One thing that could improve this slightly would be to avoid re-counting the enumerable on every iteration: for (int i=0, j=Model.Persons.Count(); i<j; i++)
Funka
Most importantly (ignoring count that can be very inefficient in some scenarios), you cannot access elements of an enumerable directly by index so the code will fail to compile for `IEnumerable<T>`.
Mehrdad Afshari
A: 

Uses LINQ Aggregate to concatenate comma-delimited links without appending a trailing comma.

<%= Model.Select(person => Html.ActionLink<PersonController>(c => c.Edit(person.PersonID), Html.Encode(person.Name))
         .Aggregate((links, link) => links + ", " + link) %>
Joe Chung