isDragTarget: boolean;
isSortable: boolean;
isMultiSortable: boolean;
+ disableTooltip: boolean;
comparator: (valueA: any, valueB: any) => number;
// True if the column was automatically generated.
defaultHiddenFields: string[];
overflowCells: boolean;
showLinkSelectors: boolean;
+ disablePaging: boolean;
+
+ // Allow calling code to know when the select-all-rows-in-page
+ // action has occurred.
+ selectRowsInPageEmitter: EventEmitter<void>;
// Services injected by our grid component
idl: IdlService;
this.store = store;
this.format = format;
this.pager = new Pager();
- this.pager.limit = 10;
this.rowSelector = new GridRowSelector();
this.toolbarButtons = [];
this.toolbarCheckboxes = [];
}
init() {
+ this.selectRowsInPageEmitter = new EventEmitter<void>();
this.columnSet = new GridColumnSet(this.idl, this.idlClass);
this.columnSet.isSortable = this.isSortable === true;
this.columnSet.isMultiSortable = this.isMultiSortable === true;
this.columnSet.defaultHiddenFields = this.defaultHiddenFields;
this.columnSet.defaultVisibleFields = this.defaultVisibleFields;
+ if (!this.pager.limit) {
+ this.pager.limit = this.disablePaging ? MAX_ALL_ROW_COUNT : 10;
+ }
this.generateColumns();
}
sortLocalData() {
const sortDefs = this.dataSource.sort.map(sort => {
+ const column = this.columnSet.getColByName(sort.name);
+
const def = {
name: sort.name,
dir: sort.dir,
- col: this.columnSet.getColByName(sort.name)
+ col: column
};
if (!def.col.comparator) {
- def.col.comparator = (a, b) => {
- if (a < b) { return -1; }
- if (a > b) { return 1; }
- return 0;
- };
+ switch (def.col.datatype) {
+ case 'id':
+ case 'money':
+ case 'int':
+ def.col.comparator = (a, b) => {
+ a = Number(a);
+ b = Number(b);
+ if (a < b) { return -1; }
+ if (a > b) { return 1; }
+ return 0;
+ };
+ break;
+ default:
+ def.col.comparator = (a, b) => {
+ if (a < b) { return -1; }
+ if (a > b) { return 1; }
+ return 0;
+ };
+ }
}
return def;
const diff = sortDef.col.comparator(valueA, valueB);
if (diff === 0) { continue; }
- console.log(valueA, valueB, diff);
-
return sortDef.dir === 'DESC' ? -diff : diff;
}
this.lastSelectedIndex = index;
}
+ selectMultipleRows(indexes: any[]) {
+ this.rowSelector.clear();
+ this.rowSelector.select(indexes);
+ this.lastSelectedIndex = indexes[indexes.length - 1];
+ }
+
// selects or deselects an item, without affecting the others.
// returns true if the item is selected; false if de-selected.
toggleSelectOneRow(index: any) {
}
}
+ // shift-up-arrow
+ // Select the previous row in addition to any currently selected row.
+ // However, if the previous row is already selected, assume the user
+ // has reversed direction and now wants to de-select the last selected row.
+ selectMultiRowsPrevious() {
+ if (!this.lastSelectedIndex) { return; }
+ const pos = this.getRowPosition(this.lastSelectedIndex);
+ const selectedIndexes = this.rowSelector.selected();
+
+ const promise = // load the previous page of data if needed
+ (pos === this.pager.offset) ? this.toPrevPage() : Promise.resolve();
+
+ promise.then(
+ ok => {
+ const row = this.dataSource.data[pos - 1];
+ const newIndex = this.getRowIndex(row);
+ if (selectedIndexes.filter(i => i === newIndex).length > 0) {
+ // Prev row is already selected. User is reversing direction.
+ this.rowSelector.deselect(this.lastSelectedIndex);
+ this.lastSelectedIndex = newIndex;
+ } else {
+ this.selectMultipleRows(selectedIndexes.concat(newIndex));
+ }
+ },
+ err => {}
+ );
+ }
+
+ // shift-down-arrow
+ // Select the next row in addition to any currently selected row.
+ // However, if the next row is already selected, assume the user
+ // has reversed direction and wants to de-select the last selected row.
+ selectMultiRowsNext() {
+ if (!this.lastSelectedIndex) { return; }
+ const pos = this.getRowPosition(this.lastSelectedIndex);
+ const selectedIndexes = this.rowSelector.selected();
+
+ const promise = // load the next page of data if needed
+ (pos === (this.pager.offset + this.pager.limit - 1)) ?
+ this.toNextPage() : Promise.resolve();
+
+ promise.then(
+ ok => {
+ const row = this.dataSource.data[pos + 1];
+ const newIndex = this.getRowIndex(row);
+ if (selectedIndexes.filter(i => i === newIndex).length > 0) {
+ // Next row is already selected. User is reversing direction.
+ this.rowSelector.deselect(this.lastSelectedIndex);
+ this.lastSelectedIndex = newIndex;
+ } else {
+ this.selectMultipleRows(selectedIndexes.concat(newIndex));
+ }
+ },
+ err => {}
+ );
+ }
+
+ getFirstRowInPage(): any {
+ return this.dataSource.data[this.pager.offset];
+ }
+
+ getLastRowInPage(): any {
+ return this.dataSource.data[this.pager.offset + this.pager.limit - 1];
+ }
+
selectFirstRow() {
- this.selectRowByPos(this.pager.offset);
+ this.selectOneRow(this.getRowIndex(this.getFirstRowInPage()));
}
selectLastRow() {
- this.selectRowByPos(this.pager.offset + this.pager.limit - 1);
+ this.selectOneRow(this.getRowIndex(this.getLastRowInPage()));
+ }
+
+ selectRowsInPage() {
+ const rows = this.dataSource.getPageOfRows(this.pager);
+ const indexes = rows.map(r => this.getRowIndex(r));
+ this.rowSelector.select(indexes);
+ this.selectRowsInPageEmitter.emit();
}
toPrevPage(): Promise<any> {
export class GridToolbarCheckbox {
label: string;
- onChange: (checked: boolean) => void;
+ isChecked: boolean;
+ onChange: EventEmitter<boolean>;
}
export class GridDataSource {
data: any[];
sort: any[];
allRowsRetrieved: boolean;
+ requestingData: boolean;
getRows: (pager: Pager, sort: any[]) => Observable<any>;
constructor() {
return Promise.resolve();
}
+ // If we have to call out for data, set inFetch
+ this.requestingData = true;
+
return new Promise((resolve, reject) => {
let idx = pager.offset;
return this.getRows(pager, this.sort).subscribe(
- row => this.data[idx++] = row,
+ row => {
+ this.data[idx++] = row;
+ this.requestingData = false;
+ },
err => {
console.error(`grid getRows() error ${err}`);
reject(err);
},
() => {
this.checkAllRetrieved(pager, idx);
+ this.requestingData = false;
resolve();
}
);