1

Following is my JSON data

   {
  "items": [
    {
      "id": 26,
      "email": "[email protected]",
      "firstName": "Poornima ",
      "lastName": "karuppu",
      "role": "Student",
      "studentDetails": {
        "discipline": "History",
        "currentDegree": "Master",
        "currentSemester": 58
      },
      "fullName": "Poornima  karuppu"
    },
    {
      "id": 149,
      "email": "[email protected]",
      "firstName": "raj",
      "lastName": "naga",
      "role": "Student",
      "studentDetails": {
        "discipline": "German Lingustics",
        "currentDegree": "Master",
        "currentSemester": 5
      },
      "fullName": "raj naga"
    },
    {
      "id": 134,
      "email": "[email protected]",
      "firstName": null,
      "lastName": null,
      "role": "Student",
      "studentDetails": {
        "discipline": "History",
        "currentDegree": "Master",
        "currentSemester": 15
      },
      "fullName": " "
    },
    {
      "id": 20,
      "email": "[email protected]",
      "firstName": "null",
      "lastName": "null",
      "role": "Student",
      "studentDetails": {
        "discipline": "History and Arts",
        "currentDegree": "Master",
        "currentSemester": 4
      },
      "fullName": "null null"
    },
    {
      "id": 184,
      "email": "[email protected]",
      "firstName": "Rob",
      "lastName": "Pat",
      "role": "Student",
      "studentDetails": {
        "discipline": "Computer Science",
        "currentDegree": "Bachelor",
        "currentSemester": 25
      },
      "fullName": "Rob Pat"
    },
    {
      "id": 151,
      "email": "[email protected]",
      "firstName": null,
      "lastName": null,
      "role": "Student",
      "studentDetails": {
        "discipline": "Art",
        "currentDegree": "Master",
        "currentSemester": 5
      },
      "fullName": " "
    },
    {
      "id": 3,
      "email": "[email protected]",
      "firstName": "Lamija",
      "lastName": "Halvadzija",
      "role": "Student",
      "studentDetails": {
        "discipline": "Lingustics",
        "currentDegree": "Master",
        "currentSemester": 5
      },
      "fullName": "Lamija Halvadzija"
    },
    {
      "id": 25,
      "email": "[email protected]",
      "firstName": "Rolans",
      "lastName": "Mustermann",
      "role": "Student",
      "studentDetails": {
        "discipline": "Linguistics",
        "currentDegree": "Bachelor",
        "currentSemester": 2
      },
      "fullName": "Rolans Mustermann"
    },
    {
      "id": 178,
      "email": "[email protected]",
      "firstName": null,
      "lastName": null,
      "role": "Student",
      "studentDetails": null,
      "fullName": " "
    },
    {
      "id": 140,
      "email": "[email protected]",
      "firstName": "Nilakshi",
      "lastName": "Naphade",
      "role": "Student",
      "studentDetails": null,
      "fullName": "NN"
    },
    {
      "id": 40,
      "email": "[email protected]",
      "firstName": "P",
      "lastName": "K",
      "role": "Student",
      "studentDetails": null,
      "fullName": "PK"
    }

  ],
}

Its a students' list that I am dispalying on UI using GET API. I am sorting these records using angular 2 pipe. Following is sort.pipe.ts code:

import { Injectable, Pipe, PipeTransform } from '@angular/core';

import { User } from '../../../core/user/user.model';

@Pipe({
  name: 'hipUsersSorter'
})
@Injectable()
export class UsersSorter implements PipeTransform {
  transform(users: any, key: string, direction: number): User[] {
    if (key !== '' && users !== null) {
      users.sort(
        (a: any, b: any) => {
          if (a[key] < b[key]) {
            return -1 * direction;
          } else if (a[key] > b[key]) {
            return 1 * direction;
          } else {
            return 0;
          }
        }
      );
    }
    return users;
  }
}

Using this pipe, I am able to sort data based on firstName, lastName and email fields. However, I am not able to sort the records based on nested attributes viz. discipline, currentDegree and currentSemester. Following is HTML template from where I am calling this sort pipe:

<table>
      <thead>
        <tr>
          <th (click)="sort('lastName')">{{ 'last name' | translate }}</th>
          <th (click)="sort('firstName')">{{ 'first name' | translate }}</th>
          <th (click)="sort('email')">{{ 'email' | translate }}</th>
          <th></th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let user of students | hipUsersFilter: query: selectedOption: selectedRole | hipUsersSorter: key: direction
                  | paginate: { id: 'server', itemsPerPage: 10, currentPage: _page, totalItems: _total }">
          <td>{{ user.lastName }}</td>
          <td>{{ user.firstName }}</td>
          <td>{{ user.email }}</td>
          <td>{{ user.studentDetails.discipline }}</td>
          <td>{{ user.studentDetails.currentDegree }}</td>
          <td>{{ user.studentDetails.currentSemester }}</td>
        </tr>
      </tbody>
    </table>

This is my sort function in component:

direction = -1;

sort(value: string) {
    this.direction = this.direction * -1;
    this.key = value;
}

How can I sort the data based on these nested fields? Can someone please provide their inputs on this issue? Thanks in advance

1

1 Answer 1

2

I'd create a method passing the obj and the nested 'path', as below:

import { Injectable, Pipe, PipeTransform } from '@angular/core';

import { User } from '../../../core/user/user.model';

@Pipe({
  name: 'hipUsersSorter'
})
@Injectable()
export class UsersSorter implements PipeTransform {
  transform(users: any, key: string, direction: number): User[] {
    if (key && users !== null && users.length > 0) {
      users.sort(
        (a: any, b: any) => {
          const propertyA: number|string = this.getProperty(a, key);
          const propertyB: number|string = this.getProperty(b, key);

          if (propertyA < propertyB) {
            return -1 * direction;
          } else if (propertyA > propertyB) {
            return 1 * direction;
          } else {
            return 0;
          }
        }
      );
    }
    return users;
  }

  private getProperty (value: { [key: string]: any}, key: string): number|string {
    if (value == null || typeof value !== 'object') {
      return undefined;
    }

    const keys: string[] = key.split('.');
    let result: any = value[keys.shift()];

    for (const key of keys) {
      if (result == null) { // check null or undefined
        return undefined;
      }

      result = result[key];
    }

    return result;
  }
}

In your template:

<th (click)="sort('studentDetails.discipline')">{{ 'discipline' | translate }}</th>
<th (click)="sort('studentDetails.currentDegree')">{{ 'degree' | translate }}</th>
<th (click)="sort('studentDetails.currentSemester')">{{ 'semester' | translate }}</th>

Simple demo: DEMO.

Sign up to request clarification or add additional context in comments.

5 Comments

It is working for the records having studentDetails not null. But my complete JSON data has many records where studentDetails = null and in this case it is not working. :(
You didn't mention it in your question :) What are you expecting for those that have null values? Feel free to fork the demo to include your null objects.
Sorry for not mentioning it. I have added all the JSON data in above question. I did not changed/forked the plunker.
Well, the method above works fine while handling null values.. your problem is probably in template.. use the safe-navigation operator this way: <td>{{ user.studentDetails?.discipline }}</td>
Hey it worked.I have somehow forgot to add a result statement in getProperty method. So the result was coming undefined. Thanks a lot :)

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.