Learning Learning - 27 days ago 13
ASP.NET (C#) Question

Creating html table dynamically with some complexity

Below is my json structure:

{
"list": [
{
"Variant": "V1",
"Id": 1,
"TestList": [
{
"SubVariantList": [
{
"Id": 10,
"Name": "A",
"Fluctuation":100
},
{
"Id": 20,
"Name": "B",
"Fluctuation":100
},
{
"Id": 30,
"Name": "C",
"Fluctuation":200
}
]
}
]
},
{
"Variant": "V2",
"Id": 2,
"TestList": [
{
"SubVariantList": [
{
"Id": 40,
"Name": "A",
"Fluctuation":1100
},
{
"Id": 50,
"Name": "B",
"Fluctuation":1200
},
{
"Id": 60,
"Name": "C",
"Fluctuation":1300
}
]
}
]
},
{
"Variant": "V3",
"Id": 3,
"TestList": [
{
"SubVariantList": [
{
"Id": 40,
"Name": "A",
"Fluctuation":500
},
{
"Id": 50,
"Name": "C",
"Fluctuation":600
}
]
}
]
}
]
}


Now with json structure i have 2 below travels:

V1:A - B - C
V2:A - C


Based on above json structure i am creating dynamic table like below:

Table1:
A - B | B - C (Headers)
VariantName AValue BValue CValue (Columns)
V1 100 100 200
V2 1100 1200 1300

Table2:
A - C (Headers)
VariantName AValue CValue (columns)
V3 500 600


I will always have subvariants in fixed order starting from 1 point like below:

A - B - C - D


First A will be fixed and rest i can have combinations like this:

A - B - C - D
A - B - C
A - C
A- D
A - B - C - D
A - B - C
A - D
A- C


Problem comes with some combinations of subvariants flow like below:

V1: A - B - C
V2 : A - B - C - D


With above data i am getting table structure like this:

Table1 : <thead>
A - B | B - C

Table2:<thead>
A - B | B - C | C - D


But already A - B and B - C structure is created in table as sequence is right so there will be only 1 table like below:

Table1 : <thead>
A - B | B - C | C - D


New table will be created only when there will be jumping like below:

A - C
A - D


This is my code:

<div>
@{
var tableHeaders = new List<string>();
for (int i = 0; i < Model.Count; i++)
{
var subvariants = string.Join(",", Model[i].TestList[0].SubVariantList.Select(cd => cd.Name)); //creating unique combination
if (tableHeaders.Count == 0)
{
tableHeaders.Add(subvariants);
}
else if (!tableHeaders.Contains(subvariants))
{
tableHeaders.Add(subvariants);
}
}
}
@for (int i = 0; i < tableHeaders.Count; i++)
{
string[] subvariants = tableHeaders[i].Split(',');
<table>
<thead>
<tr>
@for (int cnt = 0; cnt < tableHeaders.Count() - 1; cnt++) // for 2 subvariants
{
<td>
@subvariants[cnt] <span>-</span> @subvariants[cnt + 1]
</td>
}
</tr>

<tr>
<th style="border: 1px solid black;">VariantName</th>
@for (int cnt = 0; cnt < subvariants.Count() - 1; cnt++)
{
if (cnt == 0)
{
<th style="border: 1px solid black;">@subvariants[cnt]</th>
}
<th style="border: 1px solid black;">@subvariants[cnt + 1]</th>
}
</tr>
</thead>
<tbody>

@for (int m = 0; m < Model.Count; m++)
{
string subvariants = string.Join(",", Model[m].TestList[0].SubVariantList.Select(cd => cd.Name));
var headers = tableHeaders[i];
if (headers.Contains(subvariants))
{
<tr>
<td>@Model[m].Variant</td>
<td>@Model[m].TestList[0].SubVariantList[0].Value</td>
@for (int j = 1; j < Model[m].TestList[0].SubVariantList.Count; j++)
{
<td>@Model[m].TestList[0].SubVariantList[j].Value</td>
}
</tr>
}
}
</tbody>
</table>
}

</div>


Can anybody please help me as i am badly stuck in this complex logic because of various scenarios and combination of subvariants.

Answer

The first thing you need to do is to (1) remove all that logic from the view and place it in the controller where it belongs, and (2) use view models to represent how you want to display the data in the view.

Your view models should be

public class TableVM
{
    public TableVM()
    {
        Variants = new List<RowVM>();
    }
    public string Title { get; set; }
    public IEnumerable<string> Headers { get; set; }
    public List<RowVM> Variants { get; set; }
    // The following properties are used for 'grouping' your data
    public string Sequence { get; set; }
    public bool IsSequential { get; set; }
    public int MaxColumns { get; set; }
}
public class RowVM
{
    public RowVM()
    {
        Fluctuations = new List<ColumnVM>();
    }
    public string Variant { get; set; }
    public List<ColumnVM> Fluctuations { get; set; }
}
public class ColumnVM
{
    public decimal Fluctuation { get; set; }
}

which allows you to use simple loops in the view to generate each table, and within each table, a row for each Variant, and for each row, a column for each Fluctuation.

@model List<TableVM>
@foreach(var table in Model)
{
    <h4>@table.Title</h4>
    @foreach(var row in table.Variants)
    {
        <td>@row.Variant</td>
        @foreach(var column in row.Fluctuations)
        {
            <td>@column.Fluctuation</td>
        }
    }
}

Then in you controller, loop through you data and build the view model to return to the view.

To solve the issue of creating a new table for each 'group' of sequences, you can create a 'key' based on the 'group' (the Sequence property of TableVM). If the Sequence does not exist yet, add a new TableVM, other add a new TableVM

To solve the issue of including sequences ABC and ABCD in the same table, you need a method to identify if the characters in the sequence are sequential (the IsSequental property of TableVM). If you are really using those characters, then its as simple as

private bool IsSequential(string sequence)
{
    char[] c = sequence.ToCharArray();
    return c[0] + c.Length - 1 == c[c.Length - 1];
}

although that also suggest an inflexible and fragile design, and you should really consider and int property in the database for the sequence/order.

The full code is too much to post in here, but this DotNetFiddle is a working example based on the data you have shown, plus additional data for a sequence A-B-C-D. Note I found you table headers a bit confusing and have suggested an alternative in the fiddle.

Comments