From b24dabf48931d162ebdd0b95e5910931292fd4e8 Mon Sep 17 00:00:00 2001 From: Adrian Faciu Date: Sun, 24 Jul 2016 21:42:38 +0300 Subject: [PATCH] feat(typeahead): adding support for nested properties and functions for typeaheadOptionField (#777) fixes #135, fixes #523 --- components/typeahead/readme.md | 2 +- .../typeahead-container.component.ts | 4 +--- components/typeahead/typeahead-utils.ts | 22 +++++++++++++++++++ components/typeahead/typeahead.directive.ts | 22 +++---------------- 4 files changed, 27 insertions(+), 23 deletions(-) diff --git a/components/typeahead/readme.md b/components/typeahead/readme.md index 349e5ed24e..a62db90433 100644 --- a/components/typeahead/readme.md +++ b/components/typeahead/readme.md @@ -45,7 +45,7 @@ export class TypeaheadDirective implements OnInit { - `typeaheadMinLength` (`?number=1`) - minimal no of characters that needs to be entered before typeahead kicks-in. When set to 0, typeahead shows on focus with full list of options (limited as normal by typeaheadOptionsLimit) - `typeaheadWaitMs` (`?number=0`) - minimal wait time after last character typed before typeahead kicks-in - `typeaheadOptionsLimit` (`?number=20`) - maximum length of options items list - - `typeaheadOptionField` (`?string`) - name of field in array of states that contain options as objects, we use array item as option in case of this field is missing + - `typeaheadOptionField` (`?string`) - name of field in array of states that contain options as objects, we use array item as option in case of this field is missing. Supports nested properties and methods - `typeaheadAsync` (`?boolean`) - should be used only in case of `typeahead` attribute is array. If `true` - loading of options will be async, otherwise - sync. `true` make sense if options array is large. - `typeaheadLatinize` (`?boolean=true`) - match latin symbols. If `true` the word `súper` would match `super` and vice versa. - `typeaheadSingleWords` (`?boolean=true`) - break words with spaces. If `true` the text `"exact phrase" here match` would match with `match exact phrase here` but not with `phrase here exact match` (kind of "google style"). diff --git a/components/typeahead/typeahead-container.component.ts b/components/typeahead/typeahead-container.component.ts index b10c47d3bf..f3cd25589b 100644 --- a/components/typeahead/typeahead-container.component.ts +++ b/components/typeahead/typeahead-container.component.ts @@ -108,9 +108,7 @@ export class TypeaheadContainerComponent { } protected hightlight(item:any, query:string):string { - let itemStr:string = (typeof item === 'object' && this._field - ? item[this._field] - : item).toString(); + let itemStr:string = TypeaheadUtils.getValueFromObject(item, this._field); let itemStrHelper:string = (this.parent.typeaheadLatinize ? TypeaheadUtils.latinize(itemStr) : itemStr).toLowerCase(); diff --git a/components/typeahead/typeahead-utils.ts b/components/typeahead/typeahead-utils.ts index efb24155d6..33fcc007b5 100644 --- a/components/typeahead/typeahead-utils.ts +++ b/components/typeahead/typeahead-utils.ts @@ -38,4 +38,26 @@ export class TypeaheadUtils { return result; } + + public static getValueFromObject(object: any, option: string):string { + if (!option || typeof object !== 'object') { + return object.toString(); + } + + if (option.endsWith('()')) { + let functionName = option.slice(0, option.length - 2); + return object[functionName]().toString(); + } + + let properties:string = option.replace(/\[(\w+)\]/g, '.$1') + .replace(/^\./, ''); + let propertiesArray:Array = properties.split('.'); + + for (let property of propertiesArray) { + if (property in object) { + object = object[property]; + } + } + return object.toString(); + } } diff --git a/components/typeahead/typeahead.directive.ts b/components/typeahead/typeahead.directive.ts index b2db89acb8..55de490041 100644 --- a/components/typeahead/typeahead.directive.ts +++ b/components/typeahead/typeahead.directive.ts @@ -169,9 +169,7 @@ export class TypeaheadDirective implements OnInit { } public changeModel(value:any):void { - let valueStr:string = ((typeof value === 'object' && this.typeaheadOptionField) - ? value[this.typeaheadOptionField] - : value).toString(); + let valueStr:string = TypeaheadUtils.getValueFromObject(value, this.typeaheadOptionField); this.ngControl.viewToModelUpdate(valueStr); (this.ngControl.control as FormControl).updateValue(valueStr); this.hide(); @@ -262,22 +260,8 @@ export class TypeaheadDirective implements OnInit { } private prepareOption(option:any):any { - let match:any; - - if (typeof option === 'object' && - option[this.typeaheadOptionField]) { - match = this.typeaheadLatinize ? - TypeaheadUtils.latinize(option[this.typeaheadOptionField].toString()) : - option[this.typeaheadOptionField].toString(); - } - - if (typeof option === 'string') { - match = this.typeaheadLatinize ? - TypeaheadUtils.latinize(option.toString()) : - option.toString(); - } - - return match; + let match:string = TypeaheadUtils.getValueFromObject(option, this.typeaheadOptionField); + return this.typeaheadLatinize ? TypeaheadUtils.latinize(match) : match; } private normalizeQuery(value:string):any {