Order and grouping alphabetically

Viewed 10534

I need to create UI as shown below. I need to order the name alphabetically and need to group like A,B and so on.

enter image description here

I have done the first part (i.e. order the name alphabetically using lodash) as shown below.

enter image description here

contacts.html

<ion-list>
    <ion-item *ngFor="let c of contacts | async">
      <name-and-rating item-start [data]="c"></name-and-rating>
      <ion-input type="text" text-right disabled="true" [value]="c.company">
      </ion-input>
    </ion-item>
  </ion-list>

name-and-rating.html (component)

<div>
  <div>
    {{data.name}}
  </div>
  <div>
    <rating [ngModel]="data?.rating" (ngModelChange)="data.rating=$event" readOnly="true" max="5" emptyStarIconName="star-outline"
    halfStarIconName="star-half" starIconName="star" nullable="false" name="rating" item-end>
  </rating>
  </div>
</div>

add-contact.ts

 addContact() {
    this.storage.get('contacts').then((val: Contact[]) => {
      this.contacts = val;
      if (this.contacts == null) this.contacts = [];
      this.contacts.push(this.data);
      const sortedContacts = orderBy(this.contacts, [c => c.name.toLowerCase()], ['asc']);
      this.storage.set('contacts', sortedContacts).then((val: Contact[]) => {
        this.close();
      });
    });
  }

contact.ts

export class Contact {
    id: string;
    name: string;
    company: string;
    phone1: number;
    phone2: number;
    email: string;
    rating: number;
    comments: string;
}

Can you tell me how to design or implement alphabetically grouping like on the first image?

2 Answers

Create an array per key and map all sorted contacts to that key.

const contacts= [{
    name: 'Aa',
    company: 'Company name',
    locaton: 'Location',
    other: 'other'
}, {
    name: 'Aab'
}, {
    name: 'Bb'
}, {
    name: 'Cc'
}, {
    name: 'Ccc'
}, {
    name: 'Fff'
}, {
    name: 'Faa'
}, {
    name: 'Ba'
}];

const sorted = contacts.sort((a, b) => a.name > b.name ? 1 : -1);

const grouped = sorted.reduce((groups, contact) => {
    const letter = contact.name.charAt(0);

    groups[letter] = groups[letter] || [];
    groups[letter].push(contact);

    return groups;
}, {});

const result = Object.keys(grouped).map(key => ({key, contacts: grouped[key]}));

console.log(result);

Iterate over all keys and then iterate over all contacts associated with that key.

e.g.

<div *ngFor="let group of result">
    <h3>result.key</h3>
    <contact *ngFor="let contact of result.contacts" [contact]="contact"></contact>
</div>

You can use Set to generate a set of unique initials, array.reduce for the grouping and array.sort to sort alphabetically

var names = ["Daniel", "Adam", "Cesar",  "Dave", "Abraham" ].sort((a, b) => b < a ? 1: -1);
var initials = [...new Set(names.map(name => name[0]))];
var categorized = initials.reduce((m, i) => {
    m[i] = names.filter(name => name[0] === i).sort((a, b) => b < a ? 1 : -1);
    return m;
}, {});
console.log(categorized);

Then, in your component, Have Object.keys accessible in the template so you can loop through the object using *ngFor:

export class YourComponent {
  objectKeys = Object.keys;
}

<ion-list>
  <ion-item *ngFor="let category of ObjectKeys(categorized)">
    <ion-list>
      <ion-item *ngFor="let c of categorized[category]">
        <ion-input type="text" text-right disabled="true" [value]="c.company">
      </ion-item>
    </ion-list>
  </ion-item>
</ion-list>

Related