3

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

1
  • Is this possible with data received from a REST call? All I can seem to find is people posting about doing such with Static Data, so I'm confused as to if it isn't possible, or people just don't know how to do it? Commented Aug 3, 2020 at 13:30

3 Answers 3

4

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>
Sign up to request clarification or add additional context in comments.

4 Comments

Do you have plnkr or stackblitz for this? I am trying to update with my existing plnkr and looks like i need to import some RxJs for map?
next.plnkr.co/edit/… this was fun little code
Looking good. I will try it and accept your answer if it works :) Great
I have accepted. Thank you!. I am trying to add one more grouping like region before country. Like let countris = flatMap(c => c.Countries.map(s => ({Country:s, Region: c})), this.Regions); let states = flatMap(c => c.States.map(s => ({Country:c, State: s})), countris); Not sure how this is working exactly with flatMap. Could you pls give a hint or some code which works on one more level grouping? As of now it is not working with one more level
0

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

1 Comment

It does not provide the clean grouping. In your example cities are merged and user cant view clear info by city
0

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;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.