Search code examples
asp.net-mvcasp.net-mvc-4razorrenderingconditional-operator

Razor Ternary Operator to render Html Tags (ASP.NET MVC)


I'm trying to apply a responsive design to my ASP.NET MVC 4 application. I want to loop my model and render 3 items per line. Each line shall be wrapped in a div. The result should look something like this:

<div class='ResponsiveWrapper'>
    <div>
        <!-- item1 -->
    </div>
    <div>
        <!-- item2 -->
    </div>
    <div>
        <!-- item3 -->
    </div>
</div>
<div class='ResponsiveWrapper'>
    <div>
        <!-- item4 -->
    ...

In order to do so, I'm trying to use ternary operators:

@{ var i = 0; }

@foreach (var item in Model)
{
    @Html.Raw(i == 0 ? Html.Encode("<div class='section group'>") : "")
    
    <div>
        //Responsive Content comes here
    </div>

    @Html.Raw(i == 2 ? Html.Encode("</div>") : "")

    @(i<3 ? i++ : i=0)
}

Now I have 2 problems:

  1. The HTML tags which the ternary operators should render come in plain text. I tried different combinations of @Html.Raw and @Html.Encode and Strings, but it nothing worked for me

  2. It seems like the last ternary operator renders the current value of the variable i. How can I prevent this?

Additional information/code explanation

The logic already works fine:

  • The i Variable is the count variable.
  • If i = 0 I first render the start <div> tag of the wrapper and than I render the current model.item
  • If i = 1 I only render the current model.item
  • If i = 2 I first render the current model.item and than the </div> end tag

Thank you

UPDATE

Both, MajoB's and Chris Pratt's approaches basically work. Since MajoB's solution was more detailed, I went with that one. However, I had to make some modifications in order to get it to work:

  1. At the controller, I had to assure, that an IList is being returned, rather than an IEnumerable

     public ActionResult Index()
     {
         return View(db.leModel.ToList());
     }
    
  2. In the View, I had to change the signature (like 1, IList instead of IEnumerable)

     @model IList<leProject.Models.leModel>
    
  3. Various modifications in the Razor code (otherwise it would throw me exceptions)

Final code:

<div class="ResponsiveWrapper">
@for (var i = 0; i < Model.Count; i++)
{
    // the lambda expression modelItem => item.leProperty did not work for some reason. So I had to replace the item with Model[i], which means, the following line is not necessary
    { var item = Model[i]; }

    <div>
        @Html.DisplayFor(modelItem => Model[i].leProperty)
    </div>

    if ((i + 1) % 3 == 0 || i == (Model.Count - 1))
    {
        @:</div> 
        if (Model.Count + 1 - i >= 3)
        {
            @:<div class="ResponsiveWrapper">
        }
    }
}

Thank you guys :)


Solution

  • Solution without the wrapper div:

    @for(var i = 0; i < Model.Count; i++)
    {
       @{ var item = Model[i]; }      
    
       <div style="float:left;">
           <!-- item1 -->
       </div>
    
       @if((i+1) % 3 == 0)
       {
        <div style="clear:both;"></div>
       }
    }
    

    Solution with wrapper:

    <div class="ResponsiveWrapper">
    @for(var i = 0; i < Model.Count; i++)
    {
       @{ var item = Model[i]; }           
    
    
       <div>
           <!-- item1 -->
       </div>
    
       @if((i+1) % 3 == 0 || i == (Model.Count-1)) // in case you have for example 7 items in your list
       {
        @:</div> <!-- end ResponsiveWrapper -->
        @if (i != Model.Count-1)
        {
        @:<div class='ResponsiveWrapper'>
        }
       }      
    }