Developer
Developer

Reputation: 487

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

Upvotes: 3

Views: 10331

Answers (3)

Deepu Reghunath
Deepu Reghunath

Reputation: 9713

With this solution

https://stackblitz.com/edit/angular-gbhcun?file=src/app/app.component.html

Add below style to meet exact output

table, th, td {
  border: 1px solid black;
}

Upvotes: 0

Alexandr Mihalciuc
Alexandr Mihalciuc

Reputation: 2577

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>

Upvotes: 4

Akber Iqbal
Akber Iqbal

Reputation: 15041

We need to have separate columns where we run a loop based on child or sibling - you will get the idea from the comments in the code below also

relevant TS:

<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; let i = index">
            <tr>
                <!-- column 1 -->
                <td>{{country.CountryName}}</td>
                <!-- column 2 -->
                <td>
                    <ng-container *ngFor="let state of country.States">
                        <tr>
                            <td> {{state.StateName}} </td>
                        </tr>
                    </ng-container>
                </td>
                <!-- column 3 -->
                <td>
                    <ng-container *ngFor="let state of country.States">
                        <tr>
                            <td>
                                <ng-container *ngFor="let city of state.Cities">
                                    <tr>
                                        <td> {{city.CityName}} </td>
                                    </tr>
                                </ng-container>

                            </td>
                        </tr>
                    </ng-container>
                </td>

                <!-- column 4 -->
                <td>
                    <ng-container *ngFor="let state of country.States">
                        <tr>
                            <td>
                                <ng-container *ngFor="let city of state.Cities">
                                    <tr>
                                        <td>
                                            <ng-container *ngFor="let street of city.Streets">
                                                <tr>
                                                    <td>
                                                        {{street.StreetName}}

                                                    </td>
                                                </tr>
                                            </ng-container>

                                        </td>
                                    </tr>
                                </ng-container>

                            </td>
                        </tr>
                    </ng-container>
                </td>

                <!-- column 5 -->
                <td>
                    <ng-container *ngFor="let state of country.States">
                        <tr>
                            <td>
                                <ng-container *ngFor="let city of state.Cities">
                                    <tr>
                                        <td>
                                            <ng-container *ngFor="let street of city.Streets">
                                                <tr>
                                                    <td>
                                                        {{street.Male}}

                                                    </td>
                                                </tr>
                                            </ng-container>

                                        </td>
                                    </tr>
                                </ng-container>

                            </td>
                        </tr>
                    </ng-container>
                </td>

                <!-- column 6 -->
                <td>
                    <ng-container *ngFor="let state of country.States">
                        <tr>
                            <td>
                                <ng-container *ngFor="let city of state.Cities">
                                    <tr>
                                        <td>
                                            <ng-container *ngFor="let street of city.Streets">
                                                <tr>
                                                    <td>
                                                        {{street.Female}}

                                                    </td>
                                                </tr>
                                            </ng-container>

                                        </td>
                                    </tr>
                                </ng-container>

                            </td>
                        </tr>
                    </ng-container>
                </td>

                <!-- column 7 -->
                <td>
                    <ng-container *ngFor="let state of country.States">
                        <tr>
                            <td>
                                <ng-container *ngFor="let city of state.Cities">
                                    <tr>
                                        <td>
                                            <ng-container *ngFor="let street of city.Streets">
                                                <tr>
                                                    <td>
                                                        {{street.Others}}

                                                    </td>
                                                </tr>
                                            </ng-container>

                                        </td>
                                    </tr>
                                </ng-container>

                            </td>
                        </tr>
                    </ng-container>
                </td>


            </tr>

        </ng-container>
    </tbody>

</table>

working stackblitz here

Upvotes: 0

Related Questions