DataTable in TypeScript that can be sorted and filtered and what not
namespace JCB { | |
export enum SortStyle { | |
String, | |
Numeric, | |
CaseSensitiveString | |
} | |
export enum SortOrder { | |
ASC, | |
DESC | |
} | |
export class SortArgument { | |
public key: string = null; | |
public order: SortOrder = SortOrder.ASC; | |
public style: SortStyle = SortStyle.String; | |
constructor(key: string = null, order: SortOrder = SortOrder.ASC, style: SortStyle = SortStyle.String) { | |
this.key = key; | |
this.order = order; | |
this.style = style; | |
} | |
private numericCompare(valueA: number, valueB: number): number { | |
if (valueA == valueB) { | |
return 0; | |
} | |
return (this.order == SortOrder.ASC) ? | |
valueA - valueB : | |
valueB - valueA; | |
} | |
private stringCompare(valueA: string, valueB: string): number { | |
if (valueA == valueB) { | |
return 0; | |
} | |
return (this.order == SortOrder.ASC) ? | |
((valueA < valueB) ? -1 : 1) : | |
((valueA < valueB) ? 1 : -1); | |
} | |
public compare(a, b): number { | |
// Get values to compare | |
a = DataTable.isObject(a) && this.key ? a[this.key] : a; | |
b = DataTable.isObject(b) && this.key ? b[this.key] : b; | |
// Numeric sort | |
if (this.style == SortStyle.Numeric) { | |
return this.numericCompare( | |
Number(a), | |
Number(b) | |
); | |
} | |
// Case-insensitive string sort | |
else if (this.style == SortStyle.String) { | |
return this.stringCompare( | |
a.toLocaleString().toLocaleLowerCase(), | |
b.toLocaleString().toLocaleLowerCase() | |
); | |
} | |
// Case-sensitive string sort | |
else if (this.style = SortStyle.CaseSensitiveString) { | |
return this.stringCompare( | |
a.toLocaleString(), | |
b.toLocaleString() | |
); | |
} | |
return 0; | |
} | |
} | |
export class DataTable { | |
private items: Array<any> = []; | |
private sortBy: Array<SortArgument> = []; | |
constructor(items: Array<any>) { | |
this.items = items || []; | |
} | |
public static isObject(item): boolean { | |
return (item instanceof Object); | |
} | |
private sorter(table: DataTable) { | |
return function(a: any, b: any) { | |
let val: number = 0; | |
if (table.sortBy.length > 0) { | |
table.sortBy.some( | |
function(sortField: SortArgument) { | |
val = sortField.compare(a, b); | |
// If we got a value then break out | |
return (val != 0); | |
} | |
); | |
} | |
return val || 0; | |
} | |
}; | |
private static matches(row: any, key: string, pattern: any) { | |
let value = DataTable.isObject(row) ? row[key] : row; | |
// Regular expression compare | |
if (pattern instanceof RegExp) { | |
if (pattern.test(value.toString())) { | |
return true; | |
} | |
} | |
// Equality | |
else if (value == pattern) { | |
return true; | |
} | |
return false; | |
} | |
private sort(): DataTable { | |
if (this.sortBy.length > 0) { | |
this.items.sort(this.sorter(this)); | |
} | |
return this; | |
} | |
public add(row: any): DataTable { | |
this.items.push(row); | |
return this; | |
} | |
public remove(index: number): DataTable { | |
this.items = this.items.splice(index, 1); | |
return this; | |
} | |
public getSort(): Array<SortArgument> { | |
return this.sortBy; | |
} | |
public clear(): DataTable { | |
this.items = []; | |
return this; | |
} | |
public clearSort(): DataTable { | |
this.sortBy = []; | |
return this; | |
} | |
public asc(fieldName: string, style: SortStyle = SortStyle.String): DataTable { | |
this.sortBy.push( | |
new SortArgument(fieldName, SortOrder.ASC, style) | |
); | |
return this; | |
} | |
public desc(fieldName: string, style: SortStyle = SortStyle.String): DataTable { | |
this.sortBy.push( | |
new SortArgument(fieldName, SortOrder.DESC, style) | |
); | |
return this; | |
} | |
public getFirst(n: number): Array<any> { | |
return this.getAll().slice(0, n); | |
} | |
public getLast(n: number): Array<any> { | |
return this.getAll().slice(n * -1); | |
} | |
public getFrom(offset: number, limit: number): Array<any> { | |
return this.getAll().slice(offset, (offset + limit)); | |
} | |
public getAll(): Array<any> { | |
return this.sort().items; | |
} | |
public filter(key: string, pattern: any): DataTable { | |
this.items = this.search(key, pattern); | |
return this; | |
} | |
public search(key: string, pattern: any): Array<any> { | |
let matching: Array<any> = []; | |
this.sort().items.forEach(function(row) { | |
if (DataTable.matches(row, key, pattern)) { | |
matching.push(row); | |
} | |
}); | |
return matching; | |
} | |
public indexOf(key: string, pattern: any): number { | |
let index = 0, | |
firstMatch: number = -1; | |
this.sort().items.some(function(row) { | |
if (DataTable.matches(row, key, pattern)) { | |
firstMatch = index; | |
return true; | |
} | |
index++; | |
return false; | |
}); | |
return firstMatch; | |
} | |
public lastIndexOf(key: string, pattern: any): number { | |
let index: number = 0, | |
lastMatch: number = -1; | |
this.sort().items.forEach(function(row) { | |
if (DataTable.matches(row, key, pattern)) { | |
lastMatch = index; | |
} | |
index++; | |
}); | |
return lastMatch; | |
} | |
} | |
} |
<html> | |
<head> | |
<script src="datatable.js"></script> | |
</head> | |
<body> | |
<script> | |
var data = [ | |
{ name: "Jason", value: 200 }, | |
{ name: "Jason", value: 20 }, | |
{ name: "Andrew", value: 0 }, | |
{ name: "Michael", value: 100 } | |
]; | |
var table = new JCB.DataTable(data); | |
table.asc('name').asc('value', JCB.SortStyle.Numeric); | |
console.log(table.getAll()); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment