0

I'm trying to order meetings by priority [high, medium, low] but I ended up ordering them alphabetically [high, low, medium] , so how to fix this? here's the files:

sort.ts

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

@Pipe({name:'OrderBy',pure:false})

export class OrderBy implements PipeTransform {
static _orderByComparator(a:any, b:any):number{

    if((isNaN(parseFloat(a)) || !isFinite(a)) || (isNaN(parseFloat(b)) || !isFinite(b))){
        //Isn't a number so lowercase the string to properly compare
        if(a.toLowerCase() < b.toLowerCase()) return -1;
        if(a.toLowerCase() > b.toLowerCase()) return 1;
    }
    else{
        //Parse strings as numbers to compare properly
        if(parseFloat(a) < parseFloat(b)) return -1;
        if(parseFloat(a) > parseFloat(b)) return 1;
    }

    return 0; //equal each other
}
transform(input:any, [config = '+']): any{

    if(!Array.isArray(input)) return input;

    if(!Array.isArray(config) || (Array.isArray(config) && config.length == 1)){
        var propertyToCheck:string = !Array.isArray(config) ? config : config[0];
        var desc = propertyToCheck.substr(0, 1) == '-';

        //Basic array
        if(!propertyToCheck || propertyToCheck == '-' || propertyToCheck == '+'){
            return !desc ? input.sort() : input.sort().reverse();
        }
        else {
            var property:string = propertyToCheck.substr(0, 1) == '+' || propertyToCheck.substr(0, 1) == '-'
                ? propertyToCheck.substr(1)
                : propertyToCheck;

            return input.sort(function(a:any,b:any){
                return !desc
                    ? OrderBy._orderByComparator(a[property], b[property])
                    : -OrderBy._orderByComparator(a[property], b[property]);
            });
        }
    }
    else {
        //Loop over property of the array in order and sort
        return input.sort(function(a:any,b:any){
            for(var i:number = 0; i < config.length; i++){
                var desc = config[i].substr(0, 1) == '-';
                var property = config[i].substr(0, 1) == '+' || config[i].substr(0, 1) == '-'
                    ? config[i].substr(1)
                    : config[i];

                var comparison = !desc
                    ? OrderBy._orderByComparator(a[property], b[property])
                    : -OrderBy._orderByComparator(a[property], b[property]);

                //Don't return 0 yet in case of needing to sort by next property
                if(comparison != 0) return comparison;
            }

            return 0; //equal each other
        });
    }
}}

meetings.component.ts

import { Component,ChangeDetectionStrategy,Pipe, OnInit }from '@angular/core';
import { Router } from '@angular/router';

import {Meeting} from'./meeting';
import {MeetingService} from '../_services/meeting.service';
import {OrderBy} from './sort';

@Component({
moduleId: module.id,
selector: 'meetings-app',
templateUrl: 'meetings.component.html',
providers:[MeetingService,OrderBy]})

export class MeetingsComponent implements OnInit {

    priority:string[]=[
    'High',
    'Medium',
    'Low'
];
meetings : Meeting[]; //const meeting
selectedmeeting: Meeting; //class}

meetings.component.html

<div>
<p>Order by:</p>
<ul>
    <li *ngFor="let o of meetings | OrderBy:['priority']">{{o.title}} {{o.priority}}</li>
</ul>

mg22
  • 245
  • 2
  • 6
  • 13

2 Answers2

0

Pass both the property key and the array specifying the ranking to the pipe

@Pipe({name: 'orderBy'}) export class OrderByPipe {
  transform<T>(items: T[], key: keyof T, rankings?: Array<T[typeof key]>) {
    const results = items.slice();

    if (rankings) {
      return results.sort(({[key]: leftValue}, {[key]: rightValue}) => {
        const leftRank = rankings.indexOf(leftValue);
        const rightRank = rankings.indexOf(rightValue);
        return leftRank < rightRank ? 1 : leftRank === rightRank ? 0 : -1;
      });
    }
    else {
      return results.sort(({[key]: leftValue}, {[key]: rightValue}) => {
        return String(leftValue).localeCompare(String(rightValue));
      });
    }
  }
}

Usage:

<p>Order by:</p>
<ul>
  <li *ngFor="let o of meetings | OrderBy : 'priority' : priority">
    {{o.title}} {{o.priority}}
  </li>
</ul>

Since we made rankings optional, we can use this for basic ordering scenarios as well.

<p>Order by:</p>
<ul>
  <li *ngFor="let o of meetings | OrderBy : 'title'">
    {{o.title}} {{o.priority}}
  </li>
</ul>
Aluan Haddad
  • 29,886
  • 8
  • 72
  • 84
0

array.prorotype.sort accepts a comparison function which you can leverage.

The below pipe does what you are expecting

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

@Pipe({
  name: 'orderByPriority'
})
export class OrderByPriorityPipe implements PipeTransform {

  transform(value: any, ranks: string[], field: string): any {
    const res = value.slice();
    return res.sort((a, b) =>
      ranks.indexOf(a[field].toLowerCase()) -
      ranks.indexOf(b[field].toLowerCase()));
    }
}

Use it in your template like this:

<ul>
  <li *ngFor="let m of meetings | orderByPriority:priority:'priority'">
    {{ m.title }} - {{ m.priority }}
  </li>
</ul>

Here is a working plunkr using this orderBy pipe

Christopher Moore
  • 3,071
  • 4
  • 30
  • 46