Skip to content

Commit

Permalink
feat(filter/editor): add functionality to filter/sort collection (#38)
Browse files Browse the repository at this point in the history
* feat(filter/editor): add functionality to filter/sort collection
- we can now filter/sort the collection passed to the SingleSelect/MultipleSelect Editor and Filter

* fix(interface): multipleSelectOption interface is missing some arguments

* fix(build): TypeScript was reporting some build error

* refactor(code): remove any Angular references, replace by Aurelia
  • Loading branch information
ghiscoding authored Apr 2, 2018
1 parent 0bd2c53 commit 2a276a6
Show file tree
Hide file tree
Showing 22 changed files with 358 additions and 123 deletions.
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { inject } from 'aurelia-framework';
import { I18N } from 'aurelia-i18n';
import { arraysEqual } from '../services/index';
import {
Editor,
Column,
GridOption,
MultipleSelectOption,
SelectOption
} from './../models/index';
import { arraysEqual, CollectionService } from '../services/index';
import * as $ from 'jquery';

// height in pixel of the multiple-select DOM element
Expand All @@ -16,7 +16,7 @@ const SELECT_ELEMENT_HEIGHT = 26;
/**
* Slickgrid editor class for multiple select lists
*/
@inject(I18N)
@inject(CollectionService, I18N)
export class MultipleSelectEditor implements Editor {
/** The JQuery DOM element */
$editorElm: any;
Expand All @@ -36,15 +36,21 @@ export class MultipleSelectEditor implements Editor {
/** The options label/value object to use in the select list */
collection: SelectOption[] = [];

/** The property name for labels in the collection */
labelName: string;

/** The property name for values in the collection */
valueName: string;

/** The property name for labels in the collection */
labelName: string;
/** Grid options */
gridOptions: GridOption;

/** Do we translate the label? */
enableTranslateLabel: boolean;

constructor(private i18n: I18N, private args: any) {
const gridOptions = this.args.grid.getOptions() as GridOption;
const params = gridOptions.params || this.args.column.params || {};
constructor(private collectionService: CollectionService, private i18n: I18N, private args: any) {
this.gridOptions = this.args.grid.getOptions() as GridOption;
const params = this.gridOptions.params || this.args.column.params || {};

this.defaultOptions = {
container: 'body',
Expand Down Expand Up @@ -81,7 +87,32 @@ export class MultipleSelectEditor implements Editor {

this.columnDef = this.args.column;

const editorTemplate = this.buildTemplateHtmlString();
if (!this.columnDef || !this.columnDef.params || !this.columnDef.params.collection) {
throw new Error('[Aurelia-SlickGrid] You need to pass a "collection" on the params property in the column definition for ' +
'the SingleSelect Editor to work correctly. Also each option should include ' +
'a value/label pair (or value/labelKey when using Locale). For example: { params: { ' +
'{ collection: [{ value: true, label: \'True\' }, { value: false, label: \'False\'}] } } }');
}

this.enableTranslateLabel = (this.columnDef.params.enableTranslateLabel) ? this.columnDef.params.enableTranslateLabel : false;
let newCollection = this.columnDef.params.collection || [];
this.labelName = (this.columnDef.params.customStructure) ? this.columnDef.params.customStructure.label : 'label';
this.valueName = (this.columnDef.params.customStructure) ? this.columnDef.params.customStructure.value : 'value';

// user might want to filter certain items of the collection
if (this.gridOptions && this.gridOptions.params && this.columnDef.params.collectionFilterBy) {
const filterBy = this.columnDef.params.collectionFilterBy;
newCollection = this.collectionService.filterCollection(newCollection, filterBy);
}

// user might want to sort the collection
if (this.gridOptions && this.gridOptions.params && this.columnDef.params.collectionSortBy) {
const sortBy = this.columnDef.params.collectionSortBy;
newCollection = this.collectionService.sortCollection(newCollection, sortBy, this.enableTranslateLabel);
}

this.collection = newCollection;
const editorTemplate = this.buildTemplateHtmlString(newCollection);

this.createDomElement(editorTemplate);
}
Expand Down Expand Up @@ -170,28 +201,17 @@ export class MultipleSelectEditor implements Editor {
}

/** Build the template HTML string */
private buildTemplateHtmlString() {
if (!this.columnDef || !this.columnDef.params || !this.columnDef.params.collection) {
throw new Error('[Aurelia-SlickGrid] You need to pass a "collection" on the params property in the column definition for ' +
'the MultipleSelect Editor to work correctly. Also each option should include ' +
'a value/label pair (or value/labelKey when using Locale). For example: { params: { ' +
'{ collection: [{ value: true, label: \'True\' },{ value: false, label: \'False\'}] } } }');
}
this.collection = this.columnDef.params.collection || [];
this.labelName = (this.columnDef.params.customStructure) ? this.columnDef.params.customStructure.label : 'label';
this.valueName = (this.columnDef.params.customStructure) ? this.columnDef.params.customStructure.value : 'value';
const isEnabledTranslate = (this.columnDef.params.enableTranslateLabel) ? this.columnDef.params.enableTranslateLabel : false;

private buildTemplateHtmlString(collection: any[]) {
let options = '';
this.collection.forEach((option: SelectOption) => {
collection.forEach((option: SelectOption) => {
if (!option || (option[this.labelName] === undefined && option.labelKey === undefined)) {
throw new Error('A collection with value/label (or value/labelKey when using ' +
'Locale) is required to populate the Select list, for example: ' +
'{ collection: [ { value: \'1\', label: \'One\' } ])');
}
const labelKey = (option.labelKey || option[this.labelName]) as string;

const textLabel = (option.labelKey || isEnabledTranslate) ? this.i18n.tr(labelKey || ' ') : labelKey;
const textLabel = (option.labelKey || this.enableTranslateLabel) ? this.i18n.tr(labelKey || ' ') : labelKey;

options += `<option value="${option[this.valueName]}">${textLabel}</option>`;
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
MultipleSelectOption,
SelectOption
} from '../models/index';
import { findOrDefault } from '../services/index';
import { findOrDefault, CollectionService } from '../services/index';
import * as $ from 'jquery';

// height in pixel of the multiple-select DOM element
Expand All @@ -16,7 +16,7 @@ const SELECT_ELEMENT_HEIGHT = 26;
/**
* Slickgrid editor class for single select lists
*/
@inject(I18N)
@inject(CollectionService, I18N)
export class SingleSelectEditor implements Editor {
/** The JQuery DOM element */
$editorElm: any;
Expand All @@ -36,15 +36,21 @@ export class SingleSelectEditor implements Editor {
/** The options label/value object to use in the select list */
collection: SelectOption[] = [];

/** The property name for labels in the collection */
labelName: string;

/** The property name for values in the collection */
valueName: string;

/** The property name for labels in the collection */
labelName: string;
/** Grid options */
gridOptions: GridOption;

/** Do we translate the label? */
enableTranslateLabel: boolean;

constructor(private i18n: I18N, private args: any) {
const gridOptions = this.args.grid.getOptions() as GridOption;
const params = gridOptions.params || this.args.column.params || {};
constructor(private collectionService: CollectionService, private i18n: I18N, private args: any) {
this.gridOptions = this.args.grid.getOptions() as GridOption;
const params = this.gridOptions.params || this.args.column.params || {};

this.defaultOptions = {
container: 'body',
Expand Down Expand Up @@ -74,7 +80,31 @@ export class SingleSelectEditor implements Editor {

this.columnDef = this.args.column;

const editorTemplate = this.buildTemplateHtmlString();
if (!this.columnDef || !this.columnDef.params || !this.columnDef.params.collection) {
throw new Error(`[Aurelia-SlickGrid] You need to pass a "collection" on the params property in the column definition for the MultipleSelect Editor to work correctly.
Also each option should include a value/label pair (or value/labelKey when using Locale).
For example: { params: { { collection: [{ value: true, label: 'True' },{ value: false, label: 'False'}] } } }`);
}

this.enableTranslateLabel = (this.columnDef.params.enableTranslateLabel) ? this.columnDef.params.enableTranslateLabel : false;
let newCollection = this.columnDef.params.collection || [];
this.labelName = (this.columnDef.params.customStructure) ? this.columnDef.params.customStructure.label : 'label';
this.valueName = (this.columnDef.params.customStructure) ? this.columnDef.params.customStructure.value : 'value';

// user might want to filter certain items of the collection
if (this.gridOptions.params && this.columnDef.params.collectionFilterBy) {
const filterBy = this.columnDef.params.collectionFilterBy;
newCollection = this.collectionService.filterCollection(newCollection, filterBy);
}

// user might want to sort the collection
if (this.gridOptions.params && this.columnDef.params.collectionSortBy) {
const sortBy = this.columnDef.params.collectionSortBy;
newCollection = this.collectionService.sortCollection(newCollection, sortBy, this.enableTranslateLabel);
}

this.collection = newCollection;
const editorTemplate = this.buildTemplateHtmlString(newCollection);

this.createDomElement(editorTemplate);
}
Expand Down Expand Up @@ -163,27 +193,16 @@ export class SingleSelectEditor implements Editor {
}

/** Build the template HTML string */
private buildTemplateHtmlString() {
if (!this.columnDef || !this.columnDef.params || !this.columnDef.params.collection) {
throw new Error('[Aurelia-SlickGrid] You need to pass a "collection" on the params property in the column definition for ' +
'the SingleSelect Editor to work correctly. Also each option should include ' +
'a value/label pair (or value/labelKey when using Locale). For example: { params: { ' +
'{ collection: [{ value: true, label: \'True\' }, { value: false, label: \'False\'}] } } }');
}
this.collection = this.columnDef.params.collection || [];
this.labelName = (this.columnDef.params.customStructure) ? this.columnDef.params.customStructure.label : 'label';
this.valueName = (this.columnDef.params.customStructure) ? this.columnDef.params.customStructure.value : 'value';
const isEnabledTranslate = (this.columnDef.params.enableTranslateLabel) ? this.columnDef.params.enableTranslateLabel : false;

private buildTemplateHtmlString(collection: any[]) {
let options = '';
this.collection.forEach((option: SelectOption) => {
collection.forEach((option: SelectOption) => {
if (!option || (option[this.labelName] === undefined && option.labelKey === undefined)) {
throw new Error('A collection with value/label (or value/labelKey when using ' +
'Locale) is required to populate the Select list, for example: { params: { ' +
'{ collection: [ { value: \'1\', label: \'One\' } ] } } }');
}
const labelKey = (option.labelKey || option[this.labelName]) as string;
const textLabel = (option.labelKey || isEnabledTranslate) ? this.i18n.tr(labelKey || ' ') : labelKey;
const textLabel = (option.labelKey || this.enableTranslateLabel) ? this.i18n.tr(labelKey || ' ') : labelKey;

options += `<option value="${option[this.valueName]}">${textLabel}</option>`;
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,34 @@ import {
FilterArguments,
FilterCallback,
FilterType,
GridOption,
HtmlElementPosition,
MultipleSelectOption,
SearchTerm,
SelectOption
} from './../models/index';
import { CollectionService } from '../services/collection.service';
import * as $ from 'jquery';

@inject(I18N)
@inject(CollectionService, I18N)
export class MultipleSelectFilter implements Filter {
$filterElm: any;
grid: any;
gridOptions: GridOption;
searchTerms: SearchTerm[];
columnDef: Column;
callback: FilterCallback;
defaultOptions: MultipleSelectOption;
isFilled = false;
filterType = FilterType.multipleSelect;
labelName: string;
valueName: string;
enableTranslateLabel = false;

/**
* Initialize the Filter
*/
constructor(private i18n: I18N) {
constructor(private collectionService: CollectionService, private i18n: I18N) {
// default options used by this Filter, user can overwrite any of these by passing "otions"
this.defaultOptions = {
container: 'body',
Expand Down Expand Up @@ -68,8 +74,31 @@ export class MultipleSelectFilter implements Filter {
this.columnDef = args.columnDef;
this.searchTerms = args.searchTerms || [];

if (!this.grid || !this.columnDef || !this.columnDef.filter || !this.columnDef.filter.collection) {
throw new Error(`[Aurelia-SlickGrid] You need to pass a "collection" for the MultipleSelect Filter to work correctly. Also each option should include a value/label pair (or value/labelKey when using Locale). For example:: { filter: type: FilterType.multipleSelect, collection: [{ value: true, label: 'True' }, { value: false, label: 'False'}] }`);
}

this.enableTranslateLabel = this.columnDef.filter.enableTranslateLabel || false;
this.labelName = (this.columnDef.filter.customStructure) ? this.columnDef.filter.customStructure.label : 'label';
this.valueName = (this.columnDef.filter.customStructure) ? this.columnDef.filter.customStructure.value : 'value';

let newCollection = this.columnDef.filter.collection || [];
this.gridOptions = this.grid.getOptions();

// user might want to filter certain items of the collection
if (this.gridOptions.params && this.columnDef.filter.collectionFilterBy) {
const filterBy = this.columnDef.filter.collectionFilterBy;
newCollection = this.collectionService.filterCollection(newCollection, filterBy);
}

// user might want to sort the collection
if (this.gridOptions.params && this.columnDef.filter.collectionSortBy) {
const sortBy = this.columnDef.filter.collectionSortBy;
newCollection = this.collectionService.sortCollection(newCollection, sortBy, this.enableTranslateLabel);
}

// step 1, create HTML string template
const filterTemplate = this.buildTemplateHtmlString();
const filterTemplate = this.buildTemplateHtmlString(newCollection);

// step 2, create the DOM Element of the filter & pre-load search terms
// also subscribe to the onClose event
Expand Down Expand Up @@ -117,26 +146,18 @@ export class MultipleSelectFilter implements Filter {
/**
* Create the HTML template as a string
*/
private buildTemplateHtmlString() {
if (!this.columnDef || !this.columnDef.filter || !this.columnDef.filter.collection) {
throw new Error(`[Aurelia-SlickGrid] You need to pass a "collection" for the MultipleSelect Filter to work correctly. Also each option should include a value/label pair (or value/labelKey when using Locale). For example:: { filter: type: FilterType.multipleSelect, collection: [{ value: true, label: 'True' }, { value: false, label: 'False'}] }`);
}
const optionCollection = this.columnDef.filter.collection || [];
const labelName = (this.columnDef.filter.customStructure) ? this.columnDef.filter.customStructure.label : 'label';
const valueName = (this.columnDef.filter.customStructure) ? this.columnDef.filter.customStructure.value : 'value';
const isEnabledTranslate = (this.columnDef.filter.enableTranslateLabel) ? this.columnDef.filter.enableTranslateLabel : false;

private buildTemplateHtmlString(optionCollection: any[]) {
let options = '';
optionCollection.forEach((option: SelectOption) => {
if (!option || (option[labelName] === undefined && option.labelKey === undefined)) {
if (!option || (option[this.labelName] === undefined && option.labelKey === undefined)) {
throw new Error(`A collection with value/label (or value/labelKey when using Locale) is required to populate the Select list, for example:: { filter: type: FilterType.multipleSelect, collection: [ { value: '1', label: 'One' } ]')`);
}
const labelKey = (option.labelKey || option[labelName]) as string;
const selected = (this.findValueInSearchTerms(option[valueName]) >= 0) ? 'selected' : '';
const textLabel = ((option.labelKey || isEnabledTranslate) && this.i18n && typeof this.i18n.tr === 'function') ? this.i18n.tr(labelKey || ' ') : labelKey;
const labelKey = (option.labelKey || option[this.labelName]) as string;
const selected = (this.findValueInSearchTerms(option[this.valueName]) >= 0) ? 'selected' : '';
const textLabel = ((option.labelKey || this.enableTranslateLabel) && this.i18n && typeof this.i18n.tr === 'function') ? this.i18n.tr(labelKey || ' ') : labelKey;

// html text of each select option
options += `<option value="${option[valueName]}" ${selected}>${textLabel}</option>`;
options += `<option value="${option[this.valueName]}" ${selected}>${textLabel}</option>`;

// if there's a search term, we will add the "filled" class for styling purposes
if (selected) {
Expand Down
Loading

0 comments on commit 2a276a6

Please sign in to comment.