import { Observable } from 'rxjs/Observable'; import 'rxjs/add/operator/distinctUntilChanged'; import 'rxjs/add/operator/map'; import { getIn } from './get-in'; import { NgSelect } from './ng-select'; import { PropertySelector, PathSelector, FunctionSelector, Comparator } from './types'; export function select( selector?: PropertySelector | PathSelector | FunctionSelector, comparator?: Comparator): PropertyDecorator { return function decorate(target: any, key: string): void { let bindingKey = selector || _getDefaultSelector(key); if (delete target[key]) { Object.defineProperty(target, key, { get: () => _select(NgSelect.state$, bindingKey, comparator), enumerable: true, configurable: true }); } }; } /** * The default selector is the name of the property being decorated. If it ends * in the common '$' convention for Observable variables, we'll ignore the '$'. */ function _getDefaultSelector(key) { return (key.lastIndexOf('$') === key.length - 1) ? key.substring(0, key.length - 1) : key; } function _select( observable$: Observable, selector: PropertySelector | PathSelector | FunctionSelector, comparator?: Comparator): Observable { let result: Observable; if (typeof selector === 'string' || typeof selector === 'number' || typeof selector === 'symbol') { result = observable$.map(state => state[selector as PropertySelector]); } else if (Array.isArray(selector)) { result = observable$.map(state => getIn(state, selector as PathSelector)); } else { result = observable$.map(selector as FunctionSelector); } return result.distinctUntilChanged(comparator); }