Search code examples
ngforangular10

How to categories items according to some specification in angular using ngFor


I am trying to list doctors with some specialization. But the code below is creating several title with item of same specialization.

Below is my html code:

<div class="row">
        <div class="col-md-9" *ngFor="let doctor of doctors; let i = index">
            <h3 class="header-subtitle">{{doctor.doctorSpeciality}}</h3>
            <div class="doctor">
                <div class="doctor-description">
                    <h4 class="name-title">Dr. {{ doctor.doctorName}}</h4>
                </div>
            </div>
            <hr>
        </div>
</div>

The output I am getting is like:

General Physician

doctor name1

Cardiologist

doctor name2

General Physician

doctor name3

Here, the doctor name3 of category general physician should be under heading of first header title.


Solution

  • This is not something that you can achieve only in html (without some directives/pipes at least).

    I don't know exactly how you .ts code looks like, but the grouping you're seeking for needs to be made on the actual collection that you're using inside *ngFor. Most likely doctors is a flat array of objects, something like below, on which you can use reduce and map for computing the groups.

    import { Component } from '@angular/core';
    
    @Component({
      selector: 'my-app',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent {
      readonly doctors = [
        {
          doctorSpeciality: 'General Physician',
          doctorName: 'doctor name 1'
        },
        {
          doctorSpeciality: 'Cardiologist',
          doctorName: 'doctor name 2'
        },
        {
          doctorSpeciality: 'General Physician',
          doctorName: 'doctor name 3'
        }
      ];
    
      specialityGroupedDoctors = {};
    
      constructor() {
        this.computeGroups();
      }
    
      private computeGroups(): any {
        this.specialityGroupedDoctors = this.doctors.reduce(
          (acc: any, doc: any) => {
            if (!acc[doc.doctorSpeciality]) {
              acc[doc.doctorSpeciality] = [];
            }
            acc[doc.doctorSpeciality].push(doc);
            return acc;
          }, {});
      }
    }
    

    And then the html template needs to change to this:

    <div class="row">
      <div class="col-md-9" *ngFor="let group of specialityGroupedDoctors | keyvalue">
        <h3 class="header-subtitle">{{group.key}}</h3>
        <div class="doctor" *ngFor="let doctor of group.value">
          <div class="doctor-description">
            <h4 class="name-title">Dr. {{ doctor.doctorName}}</h4>
          </div>
        </div>
        <hr>
      </div>
    </div>
    

    Here you have a StackBlitz sandbox where you can see it working: https://stackblitz.com/edit/angular-ivy-t86wnc?file=src/app/app.component.html