Display data in HTML table with multi level grouping


I have to show some data in the HTML table by grouping using rowspan. Below is the expected GUI

enter image description here

I have the JSON Data like below. JSON Data here

enter image description here

Angular Code

<table class="table table-fixed" border="1">
            <thead>
               <tr>
        <th>Country</th>
        <th>State</th>
        <th>City</th>
        <th>Street</th>
        <th>Male</th>
        <th>Female</th>
        <th>Others</th>
    </tr>
            </thead>
            <tbody>
                <ng-container *ngFor="let country of Countries">
                    <tr *ngFor="let item of [].constructor(country.NoOfStreets); let streetIdx = index">
                        <ng-container *ngFor="let state of country.States; let stateIdx = index">

                            <td [attr.rowspan]="state.NoOfStreets" style="width: 15%">
                                {{state.StateName}}  
                            </td>

                        </ng-container>

                         <ng-container *ngFor="let state of country.States; let stateIdx = index">
                            <ng-container *ngFor="let city of state.Cities; let cityIdx = index">
                                <td [attr.rowspan]="city.NoOfStreets" style="width: 15%">{{city.CityName}}</td>

                                <ng-container *ngFor="let street of city.Streets; let streetIdx = index">
                                <td style="width: 15%">{{street.StreetName}}</td>
                                <td style="width: 15%">{{street.Male}}</td>
                                 <td style="width: 15%">{{street.Female}}</td>
                                  <td style="width: 15%">{{street.Others}}</td>
                            </ng-container>

                            </ng-container>
                        </ng-container>
                    </tr>
                </ng-container>
            </tbody>

        </table>

I could not able to generate the expected UI. I get the different UI and not getting rendered properly. I tried this one for almost a week and nothing worked out.

The PLUNK version is https://next.plnkr.co/edit/5nYNZ86BiWDke3GE?open=lib%2Fapp.ts&deferRun=1


Answers:


What you want is to flatten all streats into array, so that you cal loop over it. The flat code will be:

      const concat = (x,y) => x.concat(y)
      const flatMap = (f,xs) => xs.map(f).reduce(concat, [])


        let states = flatMap(c => c.States.map(s => ({Country:c, State: s})), this.Countries);
        let cities = flatMap(c => c.State.Cities.map(s => ({Country:c.Country, State:c.State, City: s})), states);

        this.streets = flatMap(c => c.City.Streets.map(str => ({Country:c.Country,     State:c.State, City: c.City, Street: str})), cities);

And then easily check if each Country, State and City is first in group like:

  <tbody>               
                <tr *ngFor="let str in streets">
                    <td *ngIf="firstCountryInGroup(str)" [rowspan]="numberOfCountry(str)">
                        {{str.Country.CountryName}}
                    </td>
                    <td *ngIf="firstStateInGroup(str)" [rowspan]="numberOfStatse(str)">
                        {{str.State.CityName}}
                    </td>
                    <td *ngIf="firstCityInGroup(str)" [rowspan]="numberOfCities(str)">
                        {{str.City.CityName}}
                    </td>
                    <td>{{str.Street.Name}}<td>
                    <td>{{str.Street.Male}}<td>
                    <td>{{str.Street.Female}}<td>
                    <td>{{str.StreetOthers}}<td>
                </tr>               
            </tbody>