31

I am trying to display a list of items that should toggle a class for styling purposes. The idea is to create a foreach loop that will cycle through all the myObj in the Model.

I tried the following code which does not work (because I'm doing it wrong)

@{ int i = 2;
   foreach(var myObj in Model)
   {
        if (i % 2 == 0)
        {
            <div class="class1">
        }
        else
        {
            <div class="class2">
        }
        Html.Partial(...);
        </div>
         i += 1;
   }     
}

What is the proper way to accomplish this?

Update
I also tried the following code that, although compiles, does not render any HTML code within (and I'm sure there are objects in Model).

@{ int i = 2;
   foreach(var myObj in Model)
   {
        if (i % 2 == 0)
        {
            @:<div class="class1">
        }
        else
        {
            @:<div class="class2">
        }
        Html.Partial(...);
        @:</div>

        i += 1;
   }

}

This is the partial class being called

<div class="class">
    <div class="class2">
        @if (string.IsNullOrEmpty(var))
        {
            @var2
        }
        else
        {
            @var
        }
    </div>
    <div class="class3">
        @var3
    </div>
</div>
<div class="class4">
    <p>var4</p>
    <ul class="class5">
        <li>element1</li>
        <li>element2</li>
    </ul>
</div>

I'm sorry I can't post the actual names and variables.

2
  • Can you be a bit more specific about how it doesn't work? Do you get output? Do you get exceptions? Commented Jun 12, 2011 at 4:33
  • To update: Can we see the partial view and the call to it please? Commented Jun 12, 2011 at 4:43

4 Answers 4

27

Let's start with improving your code.

  • Improvement step 1:

    @foreach(var myObj in Model.Select((model, index) => new { model, index }))
    {
        <div class="class@(myObj.index % 2 == 0 ? "1" : "2")">
            @Html.Partial("_Foo", myObj.model)
        </div>
    }
    
  • Improvement Step 2 (using a custom HTML helper for the class):

    @foreach(var myObj in Model.Select((model, index) => new { model, index }))
    {
        <div class="@Html.MyClass(myObj.index)">
            @Html.Partial("_Foo", myObj.model)
        </div>
    }
    

    where MyClass is defined like this:

    public static string MyClass(this HtmlHelper html, int index)
    {
        return (index % 2 == 0) ? "class1" : "class2";
    }
    
  • Improvement step 3 which is the state of the art (using Templated Razor Delegates):

    @Model.List(
        @<div class="@item.MyClass">
            @Html.Partial("_Foo", @item.Model)
        </div>
    )
    

    where the List extension method looks like this:

    public class ModelHolder<T>
    {
        public T Model { get; set; }
        public string MyClass { get; set; }
    }
    
    public static class RazorExtensions
    {
        public static HelperResult List<T>(
            this IEnumerable<T> items,
            Func<ModelHolder<T>, HelperResult> template
        )
        {
            return new HelperResult(writer =>
            {
                foreach (var item in items.Select((model, index) => new { model, index }))
                {
                    var myClass = item.index % 2 == 0 ? "class1" : "class2";
                    template(new ModelHolder<T> { Model = item.model, MyClass = myClass }).WriteTo(writer);
                }
            });
        }
    }
    

I vote for improvement number 3 which is far better and more concise than the original foreach loop.

Sign up to request clarification or add additional context in comments.

2 Comments

I went for improvement number 1 and it worked. For future reference, I did NOT test the rest.
I believe is always good to look back and consult old questions... At that time this answer looked so complicated I didn't even attempt the other improvements, now it all seems to obvious... Thanks again Darin, this was a very good answer.
19

You need to prefix the lines with non-well-formed tags with @: to prevent Razor from trying to parse the tags.
Details.

Comments

8

You may be sure there are objects in some model - but not your model : ) the following sample code derived directly from yours works just fine:


@{ int i = 2;
   string[] list = new string[] {"a","b","c","d"};
   foreach(var myObj in list)
   {
        if (i % 2 == 0){
            @:<div class="class1">
        }
        else
        {
            @:<div class="class2">
        }
        //Html.Partial(...);
        @:</div>
         i += 1;
   }     
}


Comments

0

You need to write @Html.Partial(...) to render the result to the page.

Calling Html.Partial returns a HelperResult with the partial view, but doesn't actually render it.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.