Skip to content

Commit

Permalink
feat(query): add queryFieldNameGetterFn callback know which field to use
Browse files Browse the repository at this point in the history
- in certain occasion we don't have know at hand which field name to use, we might just know depending on certain logic (e.g. if item dataContext has a product type "I" then use field "catalogNumber" but if it's type "P" use field "productCategoryNumber", ...)
  • Loading branch information
ghiscoding-SE committed Apr 23, 2020
1 parent ad73b09 commit 6d8955c
Show file tree
Hide file tree
Showing 8 changed files with 50 additions and 22 deletions.
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,7 @@ npm run test:watch
- [x] Bundle Creation (vanilla bundle)
- [ ] Eventually add Unit Tests as a PreBundle task
- [ ] Remove any Deprecated code
- [ ] Create a Migration Guide
- [ ] Create a [Migration Guide](https://github.com/ghiscoding/slickgrid-universal/wiki/Migration-for-Angular-Aurelia-Slickgrid) for Angular/Aurelia
- [ ] Add Typings for Grid & DataView objects
- [x] Add simple input bindings in the demo (e.g. pinned rows input)
- [ ] Can we change how SlickGrid Events are called and use same signature as SlickGrid instead of CustomEvent EventData signature?
- [ ] Cannot copy text from cell since it's not selectable
3 changes: 0 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@
"rebuild": "npm run clean && npm run build",
"clean": "rimraf packages/*/dist dist",
"dev:watch": "lerna run dev:watch --parallel",
"test:common:watch": "cd packages/common && npm run test:watch",
"test:excel-export:watch": "cd packages/excel-export && npm run test:watch",
"test:export:watch": "cd packages/export && npm run test:watch",
"diff": "lerna diff",
"updated": "lerna updated",
"clean:tsconfig-build-cache": "rimraf packages/*/dist/tsconfig.tsbuildinfo",
Expand Down
20 changes: 15 additions & 5 deletions packages/common/src/formatters/treeFormatter.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
import { Column, Formatter, GridOption } from './../interfaces/index';
import { getDescendantProperty } from '../services/utilities';

export const treeFormatter: Formatter = (row: number, cell: number, value: any, columnDef: Column, dataContext: any, grid: any) => {
const dataView = grid && grid.getData();
const gridOptions = grid && grid.getOptions() as GridOption;
const treeDataOptions = gridOptions?.treeDataOptions;
const treeLevelPropName = treeDataOptions?.levelPropName || '__treeLevel';
const indentMarginLeft = treeDataOptions?.indentMarginLeft || 15;
let outputValue = value;

if (value === null || value === undefined || dataContext === undefined) {
if (typeof columnDef.queryFieldNameGetterFn === 'function') {
const fieldName = columnDef.queryFieldNameGetterFn(dataContext);
if (fieldName && fieldName.indexOf('.') >= 0) {
outputValue = getDescendantProperty(dataContext, fieldName);
} else {
outputValue = dataContext.hasOwnProperty(fieldName) ? dataContext[fieldName] : value;
}
}
if (outputValue === null || outputValue === undefined || dataContext === undefined) {
return '';
}

Expand All @@ -16,20 +26,20 @@ export const treeFormatter: Formatter = (row: number, cell: number, value: any,
}

if (dataView && dataView.getIdxById && dataView.getItemByIdx) {
value = value.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
outputValue = outputValue.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
const identifierPropName = dataView.getIdPropertyName() || 'id';
const spacer = `<span style="display:inline-block; width:${indentMarginLeft * dataContext[treeLevelPropName]}px;"></span>`;
const idx = dataView.getIdxById(dataContext[identifierPropName]);
const nextItemRow = dataView.getItemByIdx(idx + 1);

if (nextItemRow && nextItemRow[treeLevelPropName] > dataContext[treeLevelPropName]) {
if (dataContext.__collapsed) {
return `${spacer}<span class="slick-group-toggle collapsed"></span>&nbsp;${value}`;
return `${spacer}<span class="slick-group-toggle collapsed"></span>&nbsp;${outputValue}`;
} else {
return `${spacer}<span class="slick-group-toggle expanded"></span>&nbsp;${value}`;
return `${spacer}<span class="slick-group-toggle expanded"></span>&nbsp;${outputValue}`;
}
}
return `${spacer}<span class="slick-group-toggle"></span>&nbsp;${value}`;
return `${spacer}<span class="slick-group-toggle"></span>&nbsp;${outputValue}`;
}
return '';
};
9 changes: 9 additions & 0 deletions packages/common/src/interfaces/column.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,15 @@ export interface Column {
*/
queryField?: string;

/**
* When you do not know at hand the name of the Field to use for querying,
* the lib will run your callback to find out which Field name you want to use by the logic you defined.
* Useful when you only know the Field name by executing a certain logic in order to get the Field name to query from.
* @param {string} item data context
* @return {string} name of the Field that will end up being used to query
*/
queryFieldNameGetterFn?: (dataContext: any) => string;

/**
* Similar to "queryField" but only used when Filtering (please note that it has higher precendence over "queryField").
* Useful when you want to display a certain field to the UI, but you want to use another field to query for Filtering.
Expand Down
13 changes: 8 additions & 5 deletions packages/common/src/services/filter.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -334,14 +334,17 @@ export class FilterService {
// }

const dataKey = columnDef.dataKey;
const fieldName = columnDef.queryFieldFilter || columnDef.queryField || columnDef.field || '';
let queryFieldName = columnDef.queryFieldFilter || columnDef.queryField || columnDef.field || '';
if (typeof columnDef.queryFieldNameGetterFn === 'function') {
queryFieldName = columnDef.queryFieldNameGetterFn(item);
}
const fieldType = columnDef.type || FieldType.string;
const filterSearchType = (columnDef.filterSearchType) ? columnDef.filterSearchType : null;
let cellValue = item[fieldName];
let cellValue = item[queryFieldName];

// when item is a complex object (dot "." notation), we need to filter the value contained in the object tree
if (fieldName && fieldName.indexOf('.') >= 0) {
cellValue = getDescendantProperty(item, fieldName);
if (queryFieldName && queryFieldName.indexOf('.') >= 0) {
cellValue = getDescendantProperty(item, queryFieldName);
}

// if we find searchTerms use them but make a deep copy so that we don't affect original array
Expand Down Expand Up @@ -442,7 +445,7 @@ export class FilterService {
const columnFilter = columnFilters[columnId] as ColumnFilter;
const conditionOptionResult = this.getFilterConditionOptionsOrBoolean(item, columnFilter, columnId, this._grid, this._dataView);

if (item.hasOwnProperty(columnId)) {
if (conditionOptionResult) {
const conditionResult = (typeof conditionOptionResult === 'boolean') ? conditionOptionResult : FilterConditions.executeMappedCondition(conditionOptionResult as FilterConditionOption);
if (conditionResult) {
// don't return true as need to check other keys in columnFilters
Expand Down
22 changes: 16 additions & 6 deletions packages/common/src/services/sort.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -320,15 +320,25 @@ export class SortService {
if (sortColumn && sortColumn.sortCol) {
const columnDef = sortColumn.sortCol;
const sortDirection = sortColumn.sortAsc ? SortDirectionNumber.asc : SortDirectionNumber.desc;
const sortField = querySortField || columnDef.queryFieldSorter || columnDef.queryField || columnDef.field;
let queryFieldName1 = querySortField || columnDef.queryFieldSorter || columnDef.queryField || columnDef.field;
let queryFieldName2 = queryFieldName1;
const fieldType = columnDef.type || FieldType.string;
let value1 = dataRow1[sortField];
let value2 = dataRow2[sortField];

// if user provided a query field name getter callback, we need to get the name on each item independently
if (typeof columnDef.queryFieldNameGetterFn === 'function') {
queryFieldName1 = columnDef.queryFieldNameGetterFn(dataRow1);
queryFieldName2 = columnDef.queryFieldNameGetterFn(dataRow2);
}

let value1 = dataRow1[queryFieldName1];
let value2 = dataRow2[queryFieldName2];

// when item is a complex object (dot "." notation), we need to filter the value contained in the object tree
if (sortField && sortField.indexOf('.') >= 0) {
value1 = getDescendantProperty(dataRow1, sortField);
value2 = getDescendantProperty(dataRow2, sortField);
if (queryFieldName1 && queryFieldName1.indexOf('.') >= 0) {
value1 = getDescendantProperty(dataRow1, queryFieldName1);
}
if (queryFieldName2 && queryFieldName2.indexOf('.') >= 0) {
value2 = getDescendantProperty(dataRow2, queryFieldName2);
}

// user could provide his own custom Sorter
Expand Down
2 changes: 1 addition & 1 deletion packages/common/src/services/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ export function deepCopy(obj: any) {
// Loop through each item in the original
// Recursively copy it's value and add to the clone
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
clone[key] = deepCopy(obj[key]);
}
}
Expand Down
Binary file not shown.

0 comments on commit 6d8955c

Please sign in to comment.