<!DOCTYPE html>
<html>

  <head>
    <title>Fuel Travel Angular2 OrderBy Pipe</title>
    <link rel="stylesheet" href="style.css" />
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/es6-shim/0.35.0/es6-sham.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.23/system-polyfills.js"></script>
    <script src="https://cdn.polyfill.io/v2/polyfill.js?features=Intl.~locale.en"></script>
    <script src="https://code.angularjs.org/2.0.0-beta.7/angular2-polyfills.js"></script>
    <script src="https://code.angularjs.org/tools/system.js"></script>
    <script src="https://code.angularjs.org/tools/typescript.js"></script>
    <script src="config.js"></script>
    <script src="https://code.angularjs.org/2.0.0-beta.7/Rx.js"></script>
    <script src="https://code.angularjs.org/2.0.0-beta.7/angular2.min.js"></script>
    <script src="https://code.angularjs.org/2.0.0-beta.7/http.min.js"></script>
    <script>
      System.import('app')
        .catch(console.error.bind(console));
    </script>
  </head>

  <body>
    <main class="container">
      <my-app>
        loading...
      </my-app>
    </main>
  </body>

</html>
/* Styles go here */

### Angular2 Starter Plunker - Typescript - Beta 0

A simple plunker demonstrating Angular2 usage:
- Uses SystemJS + TypeScript to compile on the fly
- Includes binding, directives, http, pipes, and DI usage.
System.config({
  //use typescript for compilation
  transpiler: 'typescript',
  //typescript compiler options
  typescriptOptions: {
    emitDecoratorMetadata: true
  },
  //map tells the System loader where to look for things
  map: {
    app: "./src"
  },
  //packages defines our app package
  packages: {
    app: {
      main: './main.ts',
      defaultExtension: 'ts'
    }
  }
});
//main entry point
import {bootstrap} from 'angular2/platform/browser';
import {App} from './app';

bootstrap(App, [])
  .catch(err => console.error(err));
//our root app component
import {Component,ChangeDetectionStrategy} from 'angular2/core'
import {OrderBy} from "./orderBy"

export class Person {
  constructor(public firstName: string, public lastName: string, public age: number) {}
} 

@Component({
  selector: 'my-app',
  templateUrl: 'src/app.html',
  pipes: [OrderBy],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class App {
  
    fruit: string[] = ["orange", "apple", "pear", "grape", "banana"];
    numbers: number[] = [1234, 0.214, 8675309, -1, 582];
    people: Person[] = [
  		      new Person('Linus', 'Torvalds', 46),
  					new Person('Larry', 'Ellison', 71),
            new Person('Mark', 'Zuckerberg', 31),
  					new Person('Sergey', 'Brin', 42),
            new Person('Vint', 'Cerf', 72),
            new Person('Richard', 'Stallman', 62),
            new Person('John', 'Papa', 42)
		      ];
    added: boolean = false;
    
  constructor() {}
  
  addToArrays(): void{
    this.fruit.push("new fruit");
    this.numbers.push(843);
    this.people.push(new Person('New', 'Person', 47));
    
    this.added = true;
  }
}
/*
 * Example use
 *		Basic Array of single type: *ngFor="#todo of todoService.todos | orderBy : '-'"
 *		Multidimensional Array Sort on single column: *ngFor="#todo of todoService.todos | orderBy : ['-status']"
 *		Multidimensional Array Sort on multiple columns: *ngFor="#todo of todoService.todos | orderBy : ['status', '-title']"
 */

import {Pipe, PipeTransform} from 'angular2/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
            });
        }
    }
}
<h2>OrderBy Examples</h2>
<button (click)="addToArrays()" [style.display]="added?'none':'block'" class="btn btn-primary">Add to Arrays</button>
 <section class="row m-a">
	<h3>One-Dimensional Arrays</h3>
	<div class="col-sm-4 col-md-4">
		<h4>Unordered</h4>
    <code>*ngFor="#elem of someArray"</code><br/>
		<div class="row">
		  <div class="col-sm-6 col-md-6">
    		<ul>
    			<li *ngFor="#f of fruit">{{f}}</li>
    		</ul>
		  </div>
		  <div class="col-sm-6 col-md-6">
    		<ul>
    			<li *ngFor="#n of numbers">{{n}}</li>
    		</ul>
		  </div>
		</div>
	</div>
	<div class="col-sm-4 col-md-4">
		<h4>Asc</h4>
  	<code>*ngFor="#elem of someArray | orderBy"</code><br/>
  	OR<br/>
  	<code>*ngFor="#elem of someArray | orderBy : '+'"</code><br/>
  	OR<br/>
  	<code>*ngFor="#elem of someArray | orderBy : ['+']"</code><br/>
		<div class="row">
		  <div class="col-sm-6 col-md-6">
  		  <ul>
    			<li *ngFor="#f of fruit | orderBy">{{f}}</li>
    		</ul>
		  </div>
		  <div class="col-sm-6 col-md-6">
  		  <ul>
    			<li *ngFor="#n of numbers | orderBy">{{n}}</li>
    		</ul>
		  </div>
		</div>
	</div>
	<div class="col-sm-4 col-md-4">
		<h4>Desc</h4>
  	<code>*ngFor="#elem of someArray | orderBy : '-'"</code><br/>
  	OR<br/>
  	<code>*ngFor="#elem of someArray | orderBy : ['-']"</code><br/>
		<div class="row">
		  <div class="col-sm-6 col-md-6">
  		  <ul>
    			<li *ngFor="#f of fruit | orderBy : '-'">{{f}}</li>
    		</ul>
		  </div>
		  <div class="col-sm-6 col-md-6">
  		  <ul>
    			<li *ngFor="#n of numbers | orderBy : '-'">{{n}}</li>
    		</ul>
		  </div>
		</div>
	</div>
</section>
<section class="row m-a">
	<h3>Multi-Dimensional Arrays</h3>
	<div class="col-sm-4 col-md-4">
		<h4>Unordered</h4>
		<code>*ngFor="#person of people"</code><br/>
		<ul>
			<li *ngFor="#person of people">{{person.firstName}} {{person.lastName}}, {{person.age}}</li>
		</ul>
	</div>
	<div class="col-sm-4 col-md-4">
		<h4>By Last Name Asc</h4>
		<code>*ngFor="#person of people | orderBy : 'lastName'"</code><br/>
  	OR<br/>
  	<code>*ngFor="#elem of someArray | orderBy : ['lastName']"</code><br/>
		<ul>
			<li *ngFor="#person of people | orderBy : 'lastName'">{{person.firstName}} {{person.lastName}}, {{person.age}}</li>
		</ul>
	</div>
	<div class="col-sm-4 col-md-4">
		<h4>By Age Desc Then First Name Asc</h4>
		<code>*ngFor="#person of people | orderBy : ['-age', 'firstName']"</code><br/>
		<ul>
			<li *ngFor="#person of people | orderBy : ['-age', 'firstName']">{{person.firstName}} {{person.lastName}}, {{person.age}}</li>
		</ul>
	</div>
</section>
<button (click)="addToArrays()" [style.display]="added?'none':'block'" class="btn btn-primary">Add to Arrays</button>