Skip to content

Instantly share code, notes, and snippets.

@jasonbyrne
Last active October 13, 2023 21:44
Show Gist options
  • Save jasonbyrne/c0ef4c08f5140b396159bc6651b972e5 to your computer and use it in GitHub Desktop.
Save jasonbyrne/c0ef4c08f5140b396159bc6651b972e5 to your computer and use it in GitHub Desktop.
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