I am trying to build a HTML table using WebMatrix (ASP.NET Web Pages) but am having trouble due to the way the HTML tags are opened and closed.
What I am trying to achieve is to create a table from a recordset, with three columns, and then fill in any empty columns.
This is some test code I am using to work out how to do this using WebMatrix.
<table>
@{
int row = 0;
int col = 0;
for (int i = 0; i < 20; i++) //20 cells for test purposes
{
col++;
if (col == 4)
{
col = 1;
}
if (col == 1)
{
row++;
if (row != 1)
{
</tr>
}
<tr>
}
<td>@i</td>
}
for (int i = col; i <=3; i++)
{
<td>empty</td>
}
</tr>
}
</table>
Any suggestions for how best to accomplish this.
Updated code sample based on the revised requirement:
@{
var db = Database.Open("Northwind");
var data = db.Query("SELECT * FROM Products");
var total = data.Count();
var counter = 1;
var rows = total / 3;
var spares = total % 3 > 0 ? 3 - total % 3 : 0;
if(spares > 0){
rows += 1;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<table style="border:1px solid black">
@for(var i = 1; i <= rows; i++){
if( counter % 3 == 1){
@:<tr>
}
for(var cell = 1; cell <= 3 && counter <= total; cell++){
<td style="border:1px solid black">
<div>@data.ElementAt(counter-1).ProductId</div>
<div>@data.ElementAt(counter-1).ProductName</div>
<div>@data.ElementAt(counter-1).CategoryId</div>
</td>
counter++;
}
if(counter > total && spares > 0){
for(var j = 1; j <= spares; j++){
<td style="border:1px solid black">
</td>
}
}
if(counter % 3 == 0){
@:</tr>
}
}
</table>
</body>
</html>
Hopefully, I've understood what you are after this time.
If you want to build the table from a recordset, why not do that? Here's an example using the Northwind database:
<table>
@foreach(var row in data){
<tr>
<td>@row.ProductId</td>
<td>@row.ProductName</td>
<td>@row.CategoryId</td>
</tr>
}
</table>
Or you could use the WebGrid to do this for you.
How about grouping your dataset before printing it? It ASP.NET MVC terms this is called view model. Unfortunately in WebMatrix you don't have a controller which could do the job of preparing this view model but you could do it in the codebehind or whatever this section of the Razor page is called:
@{
// group the dataset by 3 elements
var data = Enumerable.Range(0, 20).GroupBy(x => x / 3);
}
<table>
@foreach (var group in data)
{
<tr>
@foreach (var item in group)
{
<td>@item</td>
}
@for (int i = 0; i < 3 - group.Count(); i++)
{
<td>empty</td>
}
</tr>
}
</table>
and if you had a dataset of complex objects and not just integers, here's how the grouping could be done:
var dataset = Enumerable.Range(0, 20).Select(x => new { Text = "item " + x });
var data = dataset
.Select((value, index) => new { Index = index / 3, Item = value })
.GroupBy(pair => pair.Index);
and then:
<table>
@foreach (var group in data)
{
<tr>
@foreach (var element in group)
{
<td>@element.Item.Text</td>
}
@for (int i = 0; i < 3 - group.Count(); i++)
{
<td>empty</td>
}
</tr>
}
</table>
It kind of makes the code much more readable. As you can see the usage of a view model avoids you from writing ugly spaghetti code in the views.
Every-time you have some unmatched tags and you need to do integer and modulo divisions and stuff in a view you are probably doing it wrong as you didn't pick up the correct view model.