1
<table id="tblCustomItemSpecifics" cellspacing="0" cellpadding="0" class="tabs-details_table" border="0" style="border-collapse:collapse;">
                                @if (@Model.ItemSpecification != null)
                                {                                       
                                    foreach (var item in Model.ItemSpecification)
                                    {                                            

                                        <tr><td>@item.Name</td><td>@item.Value</td></tr>
                                    }
                                }
                            </table>

The Above code genertes like below for four items:

Item1 : test Item 

Item2 : test Item

item3 : test item

item4 : test item

I want to make here two column: like:

Item1 : test Item              Item2 : test Item

item3 : test item              item4 : test item

I am facing problem declaring the tag conditionally. Hope you understand the question.

1
  • Have a counter, and close and open a new row every 2 iterations. Commented Nov 16, 2015 at 15:33

3 Answers 3

2

If you always want the table to be a fixed number of columns then you can conditionally output new rows every other row by using the modulo operator. Something like this:

@for (var i = 0; i < Model.ItemSpecification.Count(); i++)
{
    if (i % 2 == 0)
    {
        <tr>
    }
    <td>@Model.ItemSpecification[i].Name</td><td>@Model.ItemSpecification[i].Value</td>
    if (i % 2 == 1)
    {
        </tr>
    }
}
if (Model.ItemSpecification.Count() % 2 != 0)
{
    <td></td></tr>
}

This should emit the <tr> and </tr> tags every alternating iteration of the loop, rather than every iteration. (Since i % 2 will only equal 0 when i is evenly divisible by 2.) This should also be adding an empty item at the end for odd-numbered lists.

Note that this is very free-hand code, you may need to do some tweaking. But the point remains the same. For however many columns you have, you'd check your counter (i) to know if it's time to add a new column. Then have some logic at the end of the loop to clean up the table to account for uneven row counts.

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

5 Comments

so... with odd number of items last row will not be closed?
I have tried this technique befor, int i=0, then in one condition set i =0; and in other i=1; if i =0 , then <tr> starts & if i = 1, </tr> ends. and outside the foreach, i checked the i's value, if its 1 ,then added a </tr> tag. This is cause there may be three items also. PROBLEM is, after defining <tr> tag alone everything next to it become clientside... the if conditions after that turned into just string.
@AbdurRahim: I think you're right, and I just changed one of the conditions as you were typing that. Admittedly this is free-hand code and I don't have a scenario in front of me to test it. But the idea is the same regardless of the details. Simply use a counter to determine when a new row needs to begin.
@AbdurRahim: Do you just mean that the Razor syntax isn't discerning server-side code properly? That can be fixed by using the @ symbol when code is mistakenly interpreted as client-side, and using <text></text> tags when code is mistakenly interpreted as server-side. The Razor syntax itself doesn't prevent this logic. You just need to specify client-side and server-side code sometimes when the engine gets mixed up.
Use @:<tr> and @:</tr>. Be aware that you'll get warnings because the Razor parser can't determine that the tr tags are properly located and closed. This is where using Html.Raw can help.
1

What you need here is just 'batch' your items into batches of size 2. You can do it either in view or (better) in controller. Easiest way is to use morelinq for batching:

int columnsCount = 2;
var rows = Model.ItemSpecification.Batch(columnsCount);

Or you can do it manually:

@{ 
  var columnsCount = 2;
  var rows = from x in Model.ItemSpecification.Select((item, index) => new { item, index })
             group x by x.index / columnsCount into g
             select g.OrderBy(x => x.index).Select(x => x.item);
}

After that displaying rows is very simple:

<table>
    <tbody>
        @foreach (var row in rows)
        {
            <tr>
                @foreach (var item in row)
                {
                    <td>@item.Name</td><td>@item.Value</td>
                }
            </tr>
        }
    </tbody>
</table>

NOTE: Thus you only need to change the position of items displayed on page then probably table is not best way for that. E.g. you can use something like Bootstrap grid system (or write your own css that pushes second column items to the right).

1 Comment

This is really elegant and will work well for small lists. Not sure it will work as well when the list grows. Still large lists should be paginated prior to displaying. That being the case, I upvoted this.
1

You will need to generate rows via a counter and html.raw.

@{ var columns = 2; }
<table id="tblCustomItemSpecifics" cellspacing="0" cellpadding="0" class="tabs-details_table" border="0" style="border-collapse:collapse;">
      @if (@Model.ItemSpecification != null)
      {
          var column = -1;                                        
          <tr>
          foreach (var item in Model.ItemSpecification)
          {
              if ( ++column % columns == 0 ) {
                  @Html.Raw("</tr><tr>")
              }
              <td>@item.Name</td><td>@item.Value</td>
          }
          </tr>
      }
</table>

If you want to flow the columns down instead of across, call this extension method first:

public static List<T> Sort<T, U>(this List<T> Source, Func<T, U> OrderFunc) { return Source.OrderBy(OrderFunc).ToList(); }

/// <summary>
/// Sorts lists down the specified number of columns
/// for instance:
/// 1  4  7
/// 2  5  8
/// 3  6  9
/// 
/// instead of:
/// 1  2  3
/// 4  5  6
/// 7  8  9
public static List<T> ColumnSort<T, U>(this List<T> Source, Func<T, U> OrderFunc, int NumColumns) where T : new() {
    var sorted = Source.Sort(OrderFunc);
    var m = (int)Math.Ceiling(sorted.Count / (double)NumColumns);
    var n = NumColumns;
    var flipped = new T[m*n];
    for (var i = 0; i < sorted.Count; i++ )
    {
        var t = i % m * n + i / m;
        flipped[t] = sorted[i];
    }
    return flipped.ToList();
}

Example usage:

          foreach (var item in Model.ItemSpecification.ToList().ColumnSort(itemSpec => itemSpec.Name,columns)
          {
              if ( ++column % columns == 0 ) {
                  @Html.Raw("</tr><tr>")
              }
              <td>@item.Name</td><td>@item.Value</td>
          }

Here is a Fiddle

3 Comments

Its working... but the first item is coming last and the last is first I have not implemented the server side code..
Add an OrderBy for your foreach: Model.ItemSpecification.OrderBy(is => is.Name)
I added a fiddle and tweaked this a bit, setting the starting column = -1

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.