UNPKG

ng2-bootstrap

Version:
282 lines (281 loc) 12.1 kB
"use strict"; var core_1 = require('@angular/core'); var forms_1 = require('@angular/forms'); var typeahead_container_component_1 = require('./typeahead-container.component'); var typeahead_options_class_1 = require('./typeahead-options.class'); var typeahead_utils_1 = require('./typeahead-utils'); var Observable_1 = require('rxjs/Observable'); require('rxjs/add/observable/from'); require('rxjs/add/operator/debounceTime'); require('rxjs/add/operator/filter'); require('rxjs/add/operator/map'); require('rxjs/add/operator/mergeMap'); require('rxjs/add/operator/toArray'); var components_helper_service_1 = require('../utils/components-helper.service'); /* tslint:disable-next-line */ var KeyboardEvent = global.KeyboardEvent; var TypeaheadDirective = (function () { function TypeaheadDirective(control, viewContainerRef, element, renderer, componentsHelper) { this.typeaheadLoading = new core_1.EventEmitter(false); this.typeaheadNoResults = new core_1.EventEmitter(false); this.typeaheadOnSelect = new core_1.EventEmitter(false); this.typeaheadMinLength = void 0; this.typeaheadAsync = void 0; this.typeaheadLatinize = true; this.typeaheadSingleWords = true; this.typeaheadWordDelimiters = ' '; this.typeaheadPhraseDelimiters = '\'"'; this.isTypeaheadOptionsListActive = false; this.keyUpEventEmitter = new core_1.EventEmitter(); this.placement = 'bottom-left'; this.element = element; this.ngControl = control; this.viewContainerRef = viewContainerRef; this.renderer = renderer; this.componentsHelper = componentsHelper; } TypeaheadDirective.prototype.onChange = function (e) { if (this.container) { // esc if (e.keyCode === 27) { this.hide(); return; } // up if (e.keyCode === 38) { this.container.prevActiveMatch(); return; } // down if (e.keyCode === 40) { this.container.nextActiveMatch(); return; } // enter if (e.keyCode === 13) { this.container.selectActiveMatch(); return; } } // For `<input>`s, use the `value` property. For others that don't have a // `value` (such as `<span contenteditable="true">`, use `innerText`. var value = e.target.value !== undefined ? e.target.value : e.target.innerText; if (value.trim().length >= this.typeaheadMinLength) { this.typeaheadLoading.emit(true); this.keyUpEventEmitter.emit(e.target.value); } else { this.typeaheadLoading.emit(false); this.typeaheadNoResults.emit(false); this.hide(); } }; TypeaheadDirective.prototype.onFocus = function () { if (this.typeaheadMinLength === 0) { this.typeaheadLoading.emit(true); this.keyUpEventEmitter.emit(''); } }; TypeaheadDirective.prototype.onBlur = function () { if (this.container && !this.container.isFocused) { this.hide(); } }; TypeaheadDirective.prototype.onKeydown = function (e) { // no container - no problems if (!this.container) { return; } // if items is visible - prevent form submition if (e.keyCode === 13) { e.preventDefault(); return; } // if tab default browser behavior will select next input field, and therefore we should close the items list if (e.keyCode === 9) { this.hide(); return; } }; TypeaheadDirective.prototype.ngOnInit = function () { this.typeaheadOptionsLimit = this.typeaheadOptionsLimit || 20; this.typeaheadMinLength = this.typeaheadMinLength === void 0 ? 1 : this.typeaheadMinLength; this.typeaheadWaitMs = this.typeaheadWaitMs || 0; // async should be false in case of array if (this.typeaheadAsync === undefined && !(this.typeahead instanceof Observable_1.Observable)) { this.typeaheadAsync = false; } if (this.typeahead instanceof Observable_1.Observable) { this.typeaheadAsync = true; } if (this.typeaheadAsync) { this.asyncActions(); } else { this.syncActions(); } }; TypeaheadDirective.prototype.changeModel = function (value) { var valueStr = typeahead_utils_1.TypeaheadUtils.getValueFromObject(value, this.typeaheadOptionField); this.ngControl.viewToModelUpdate(valueStr); this.ngControl.control.setValue(valueStr); this.hide(); }; Object.defineProperty(TypeaheadDirective.prototype, "matches", { get: function () { return this._matches; }, enumerable: true, configurable: true }); TypeaheadDirective.prototype.show = function (matches) { var options = new typeahead_options_class_1.TypeaheadOptions({ typeaheadRef: this, placement: this.placement, animation: false }); var binding = core_1.ReflectiveInjector.resolve([ { provide: typeahead_options_class_1.TypeaheadOptions, useValue: options } ]); this.popup = this.componentsHelper .appendNextToLocation(typeahead_container_component_1.TypeaheadContainerComponent, this.viewContainerRef, binding); this.popup.instance.position(this.viewContainerRef.element); this.container = this.popup.instance; this.container.parent = this; // This improves the speedas it won't have to be done for each list item var normalizedQuery = (this.typeaheadLatinize ? typeahead_utils_1.TypeaheadUtils.latinize(this.ngControl.control.value) : this.ngControl.control.value).toString() .toLowerCase(); this.container.query = this.typeaheadSingleWords ? typeahead_utils_1.TypeaheadUtils.tokenize(normalizedQuery, this.typeaheadWordDelimiters, this.typeaheadPhraseDelimiters) : normalizedQuery; this.container.matches = matches; this.container.field = this.typeaheadOptionField; this.element.nativeElement.focus(); }; TypeaheadDirective.prototype.hide = function () { if (this.container) { this.popup.destroy(); this.container = void 0; } }; TypeaheadDirective.prototype.asyncActions = function () { var _this = this; this.keyUpEventEmitter .debounceTime(this.typeaheadWaitMs) .mergeMap(function () { return _this.typeahead; }) .subscribe(function (matches) { _this._matches = matches.slice(0, _this.typeaheadOptionsLimit); _this.finalizeAsyncCall(); }, function (err) { console.error(err); }); }; TypeaheadDirective.prototype.syncActions = function () { var _this = this; this.keyUpEventEmitter .debounceTime(this.typeaheadWaitMs) .mergeMap(function (value) { var normalizedQuery = _this.normalizeQuery(value); return Observable_1.Observable.from(_this.typeahead) .filter(function (option) { return option && _this.testMatch(_this.prepareOption(option).toLowerCase(), normalizedQuery); }) .toArray(); }) .subscribe(function (matches) { _this._matches = matches.slice(0, _this.typeaheadOptionsLimit); _this.finalizeAsyncCall(); }, function (err) { console.error(err); }); }; TypeaheadDirective.prototype.prepareOption = function (option) { var match = typeahead_utils_1.TypeaheadUtils.getValueFromObject(option, this.typeaheadOptionField); return this.typeaheadLatinize ? typeahead_utils_1.TypeaheadUtils.latinize(match) : match; }; TypeaheadDirective.prototype.normalizeQuery = function (value) { // If singleWords, break model here to not be doing extra work on each iteration var normalizedQuery = (this.typeaheadLatinize ? typeahead_utils_1.TypeaheadUtils.latinize(value) : value) .toString() .toLowerCase(); normalizedQuery = this.typeaheadSingleWords ? typeahead_utils_1.TypeaheadUtils.tokenize(normalizedQuery, this.typeaheadWordDelimiters, this.typeaheadPhraseDelimiters) : normalizedQuery; return normalizedQuery; }; TypeaheadDirective.prototype.testMatch = function (match, test) { var spaceLength; if (typeof test === 'object') { spaceLength = test.length; for (var i = 0; i < spaceLength; i += 1) { if (test[i].length > 0 && match.indexOf(test[i]) < 0) { return false; } } return true; } else { return match.indexOf(test) >= 0; } }; TypeaheadDirective.prototype.finalizeAsyncCall = function () { this.typeaheadLoading.emit(false); this.typeaheadNoResults.emit(this.matches.length <= 0); if (this._matches.length <= 0) { this.hide(); return; } if (this.container && this._matches.length > 0) { // This improves the speedas it won't have to be done for each list item var normalizedQuery = (this.typeaheadLatinize ? typeahead_utils_1.TypeaheadUtils.latinize(this.ngControl.control.value) : this.ngControl.control.value).toString() .toLowerCase(); this.container.query = this.typeaheadSingleWords ? typeahead_utils_1.TypeaheadUtils.tokenize(normalizedQuery, this.typeaheadWordDelimiters, this.typeaheadPhraseDelimiters) : normalizedQuery; this.container.matches = this._matches; } if (!this.container && this._matches.length > 0) { this.show(this._matches); } }; TypeaheadDirective.decorators = [ { type: core_1.Directive, args: [{ /* tslint:disable */ selector: '[typeahead][ngModel],[typeahead][formControlName]' },] }, ]; /** @nocollapse */ TypeaheadDirective.ctorParameters = [ { type: forms_1.NgControl, }, { type: core_1.ViewContainerRef, }, { type: core_1.ElementRef, }, { type: core_1.Renderer, }, { type: components_helper_service_1.ComponentsHelper, }, ]; TypeaheadDirective.propDecorators = { 'typeaheadLoading': [{ type: core_1.Output },], 'typeaheadNoResults': [{ type: core_1.Output },], 'typeaheadOnSelect': [{ type: core_1.Output },], 'typeahead': [{ type: core_1.Input },], 'typeaheadMinLength': [{ type: core_1.Input },], 'typeaheadWaitMs': [{ type: core_1.Input },], 'typeaheadOptionsLimit': [{ type: core_1.Input },], 'typeaheadOptionField': [{ type: core_1.Input },], 'typeaheadAsync': [{ type: core_1.Input },], 'typeaheadLatinize': [{ type: core_1.Input },], 'typeaheadSingleWords': [{ type: core_1.Input },], 'typeaheadWordDelimiters': [{ type: core_1.Input },], 'typeaheadPhraseDelimiters': [{ type: core_1.Input },], 'typeaheadItemTemplate': [{ type: core_1.Input },], 'onChange': [{ type: core_1.HostListener, args: ['keyup', ['$event'],] },], 'onFocus': [{ type: core_1.HostListener, args: ['focus', ['$event.target'],] },], 'onBlur': [{ type: core_1.HostListener, args: ['blur',] },], 'onKeydown': [{ type: core_1.HostListener, args: ['keydown', ['$event'],] },], }; return TypeaheadDirective; }()); exports.TypeaheadDirective = TypeaheadDirective;