Search code examples
c#foreachhtmlgenericcontrol

Combine Foreach loop and counter to add dynamically generated html to the beginning and end of every nth row


I am dynamically generating HtmlGeneric Controls with data in a DataTable. I need to concatenate HTML to the beginning and end of each group of 3. For example, my table looks something like this:

Title           Body
------------------------------
Order 1     This is body 1
Order 2     This is body 2
Order 3     This is body 3
Order 4     This is body 4
Order 5     This is body 5
Order 6     This is body 6

I'm currently generating HTML like this with no issue:

<div class="card">
  <div class="card-body">
    <h5 class="card-title">Order 1</h5>
    <p class="card-text">This is body 1</p>
  </div>
</div>

<div class="card">
  <div class="card-body">
    <h5 class="card-title">Order 2</h5>
    <p class="card-text">This is body 2</p>
  </div>
</div>

<div class="card">
  <div class="card-body">
    <h5 class="card-title">Order 3</h5>
    <p class="card-text">This is body 3</p>
  </div>
</div>

<div class="card">
  <div class="card-body">
    <h5 class="card-title">Order 4</h5>
    <p class="card-text">This is body 4</p>
  </div>
</div>

<div class="card">
  <div class="card-body">
    <h5 class="card-title">Order 5</h5>
    <p class="card-text">This is body 5</p>
  </div>
</div>

<div class="card">
  <div class="card-body">
    <h5 class="card-title">Order 6</h5>
    <p class="card-text">This is body 6</p>
  </div>
</div>

I need to combine a foreach loop and a counter to concatenate a div with a card-group class at the beginning and end of every 3 cards like this. Of course, in reality there are a lot more rows than 6.:

<div class="card-group">
    <div class="card">
      <div class="card-body">
        <h5 class="card-title">Order 1</h5>
        <p class="card-text">This is body 1</p>
      </div>
    </div>
    
    <div class="card">
      <div class="card-body">
        <h5 class="card-title">Order 2</h5>
        <p class="card-text">This is body 2</p>
      </div>
    </div>
    
    <div class="card">
      <div class="card-body">
        <h5 class="card-title">Order 3</h5>
        <p class="card-text">This is body 3</p>
      </div>
    </div>
</div>
<div class="card-group">
    <div class="card">
      <div class="card-body">
        <h5 class="card-title">Order 4</h5>
        <p class="card-text">This is body 4</p>
      </div>
    </div>
    
    <div class="card">
      <div class="card-body">
        <h5 class="card-title">Order 5</h5>
        <p class="card-text">This is body 5</p>
      </div>
    </div>
    
    <div class="card">
      <div class="card-body">
        <h5 class="card-title">Order 6</h5>
        <p class="card-text">This is body 6</p>
      </div>
    </div>
</div>

It's very simple without the need for concatenating the additional HTML. This is executed in my page load method:

DataTable dtCards = GetData();
foreach (DataRow row in dtCards.Rows)
{
    var titleText = row["Title"].ToString();
    var bodyText = row["Body"].ToString();
    CreateDiv(titleText, bodyText); //method to create HmtlGeneric Controls
}

            

I'm assuming I'll need to combine a foreach loop with a counter inside the CreateDiv method but cannot wrap my mind around how exactly that will work out. Especially if there's an odd number of rows - the card-group div would always need a closing tag on the final row.


Solution

  • Shane, what you are essentially doing is Paging through your Rows in your table, so focus on Skip and Take Linq extension methods. Below is a hasty sample

    void Main()
    {
        // Data table that we are trying to page trough 
        List<string> rows = new List<string>() 
        {
            " title1,body1 ",
            " title2,body2 ",
            " title3,body3 ",
            " title4,body4 ",
            " title5,body5 ",
            " title6,body6 ",
            " title7,body7 "
        };
        
        //Result after paging 
        List<string> group = new List<string>();
        
        // Set your page size or pass in as a parameter
        int numberOfObjectsPerPage = 3;
        
        decimal totalRows = rows.Count; 
        int pages = (int) Math.Ceiling(totalRows/numberOfObjectsPerPage);
        
            
        for(int i=0;i<pages;i++)
        {       
                
                string rowText = "";
                
                // Get the rows in that page Focus on the Skip and Take methods
                var tempRows = rows.Skip(i * numberOfObjectsPerPage).Take(numberOfObjectsPerPage);
                
                // Now foreach page do something here
                foreach(var row in tempRows)
                {
                    rowText = rowText + row.ToString();
                }
                
                group.Add("div group" + rowText + "/div" );
                
        };
    
        group.ForEach( g => 
        {
             Console.WriteLine(g);
        });
    }
    
    

    you get something like this.

    div group title1,body1  title2,body2  title3,body3 /div
    div group title4,body4  title5,body5  title6,body6 /div
    div group title7,body7 /div