UNPKG

primeng

Version:

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![npm version](https://badge.fury.io/js/primeng.svg)](https://badge.fury.io/js/primeng) [![Build Status](https://travis-ci.org/primefaces/primeng.

755 lines (751 loc) 29.2 kB
import { forwardRef, EventEmitter, ElementRef, Renderer2, ChangeDetectorRef, IterableDiffers, Input, Output, ViewChild, ContentChildren, Component, ChangeDetectionStrategy, NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { trigger, state, style, transition, animate } from '@angular/animations'; import { InputTextModule } from 'primeng/inputtext'; import { ButtonModule } from 'primeng/button'; import { PrimeTemplate, SharedModule } from 'primeng/api'; import { DomHandler } from 'primeng/dom'; import { UniqueComponentId, ObjectUtils } from 'primeng/utils'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; const AUTOCOMPLETE_VALUE_ACCESSOR = { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => AutoComplete), multi: true }; let AutoComplete = class AutoComplete { constructor(el, renderer, cd, differs) { this.el = el; this.renderer = renderer; this.cd = cd; this.differs = differs; this.minLength = 1; this.delay = 300; this.type = 'text'; this.autoZIndex = true; this.baseZIndex = 0; this.dropdownIcon = "pi pi-caret-down"; this.unique = true; this.completeOnFocus = false; this.completeMethod = new EventEmitter(); this.onSelect = new EventEmitter(); this.onUnselect = new EventEmitter(); this.onFocus = new EventEmitter(); this.onBlur = new EventEmitter(); this.onDropdownClick = new EventEmitter(); this.onClear = new EventEmitter(); this.onKeyUp = new EventEmitter(); this.onShow = new EventEmitter(); this.onHide = new EventEmitter(); this.scrollHeight = '200px'; this.dropdownMode = 'blank'; this.showTransitionOptions = '225ms ease-out'; this.hideTransitionOptions = '195ms ease-in'; this.autocomplete = 'off'; this.onModelChange = () => { }; this.onModelTouched = () => { }; this.overlayVisible = false; this.focus = false; this.inputFieldValue = null; this.differ = differs.find([]).create(null); this.listId = UniqueComponentId() + '_list'; } get suggestions() { return this._suggestions; } set suggestions(val) { this._suggestions = val; this.handleSuggestionsChange(); } ngAfterViewChecked() { //Use timeouts as since Angular 4.2, AfterViewChecked is broken and not called after panel is updated if (this.suggestionsUpdated && this.overlay && this.overlay.offsetParent) { setTimeout(() => { if (this.overlay) { this.alignOverlay(); } }, 1); this.suggestionsUpdated = false; } if (this.highlightOptionChanged) { setTimeout(() => { if (this.overlay) { let listItem = DomHandler.findSingle(this.overlay, 'li.ui-state-highlight'); if (listItem) { DomHandler.scrollInView(this.overlay, listItem); } } }, 1); this.highlightOptionChanged = false; } } handleSuggestionsChange() { if (this._suggestions != null && this.loading) { this.highlightOption = null; if (this._suggestions.length) { this.noResults = false; this.show(); this.suggestionsUpdated = true; if (this.autoHighlight) { this.highlightOption = this._suggestions[0]; } } else { this.noResults = true; if (this.emptyMessage) { this.show(); this.suggestionsUpdated = true; } else { this.hide(); } } this.loading = false; } } ngAfterContentInit() { this.templates.forEach((item) => { switch (item.getType()) { case 'item': this.itemTemplate = item.template; break; case 'selectedItem': this.selectedItemTemplate = item.template; break; default: this.itemTemplate = item.template; break; } }); } writeValue(value) { this.value = value; this.filled = this.value && this.value != ''; this.updateInputField(); } registerOnChange(fn) { this.onModelChange = fn; } registerOnTouched(fn) { this.onModelTouched = fn; } setDisabledState(val) { this.disabled = val; } onInput(event) { // When an input element with a placeholder is clicked, the onInput event is invoked in IE. if (!this.inputKeyDown && DomHandler.isIE()) { return; } if (this.timeout) { clearTimeout(this.timeout); } let value = event.target.value; if (!this.multiple && !this.forceSelection) { this.onModelChange(value); } if (value.length === 0 && !this.multiple) { this.hide(); this.onClear.emit(event); this.onModelChange(value); } if (value.length >= this.minLength) { this.timeout = setTimeout(() => { this.search(event, value); }, this.delay); } else { this.suggestions = null; this.hide(); } this.updateFilledState(); this.inputKeyDown = false; } onInputClick(event) { if (this.documentClickListener) { this.inputClick = true; } } search(event, query) { //allow empty string but not undefined or null if (query === undefined || query === null) { return; } this.loading = true; this.completeMethod.emit({ originalEvent: event, query: query }); } selectItem(option, focus = true) { if (this.forceSelectionUpdateModelTimeout) { clearTimeout(this.forceSelectionUpdateModelTimeout); this.forceSelectionUpdateModelTimeout = null; } if (this.multiple) { this.multiInputEL.nativeElement.value = ''; this.value = this.value || []; if (!this.isSelected(option) || !this.unique) { this.value = [...this.value, option]; this.onModelChange(this.value); } } else { this.inputEL.nativeElement.value = this.field ? ObjectUtils.resolveFieldData(option, this.field) || '' : option; this.value = option; this.onModelChange(this.value); } this.onSelect.emit(option); this.updateFilledState(); if (focus) { this.itemClicked = true; this.focusInput(); } } show() { if (this.multiInputEL || this.inputEL) { let hasFocus = this.multiple ? document.activeElement == this.multiInputEL.nativeElement : document.activeElement == this.inputEL.nativeElement; if (!this.overlayVisible && hasFocus) { this.overlayVisible = true; } } } onOverlayAnimationStart(event) { switch (event.toState) { case 'visible': this.overlay = event.element; this.appendOverlay(); if (this.autoZIndex) { this.overlay.style.zIndex = String(this.baseZIndex + (++DomHandler.zindex)); } this.alignOverlay(); this.bindDocumentClickListener(); this.bindDocumentResizeListener(); this.onShow.emit(event); break; case 'void': this.onOverlayHide(); break; } } onOverlayAnimationDone(event) { if (event.toState === 'void') { this._suggestions = null; } } appendOverlay() { if (this.appendTo) { if (this.appendTo === 'body') document.body.appendChild(this.overlay); else DomHandler.appendChild(this.overlay, this.appendTo); this.overlay.style.minWidth = DomHandler.getWidth(this.el.nativeElement.children[0]) + 'px'; } } resolveFieldData(value) { return this.field ? ObjectUtils.resolveFieldData(value, this.field) : value; } restoreOverlayAppend() { if (this.overlay && this.appendTo) { this.el.nativeElement.appendChild(this.overlay); } } alignOverlay() { if (this.appendTo) DomHandler.absolutePosition(this.overlay, (this.multiple ? this.multiContainerEL.nativeElement : this.inputEL.nativeElement)); else DomHandler.relativePosition(this.overlay, (this.multiple ? this.multiContainerEL.nativeElement : this.inputEL.nativeElement)); } hide() { this.overlayVisible = false; } handleDropdownClick(event) { this.focusInput(); let queryValue = this.multiple ? this.multiInputEL.nativeElement.value : this.inputEL.nativeElement.value; if (this.dropdownMode === 'blank') this.search(event, ''); else if (this.dropdownMode === 'current') this.search(event, queryValue); this.onDropdownClick.emit({ originalEvent: event, query: queryValue }); } focusInput() { if (this.multiple) this.multiInputEL.nativeElement.focus(); else this.inputEL.nativeElement.focus(); } removeItem(item) { let itemIndex = DomHandler.index(item); let removedValue = this.value[itemIndex]; this.value = this.value.filter((val, i) => i != itemIndex); this.onModelChange(this.value); this.updateFilledState(); this.onUnselect.emit(removedValue); } onKeydown(event) { if (this.overlayVisible) { let highlightItemIndex = this.findOptionIndex(this.highlightOption); switch (event.which) { //down case 40: if (highlightItemIndex != -1) { var nextItemIndex = highlightItemIndex + 1; if (nextItemIndex != (this.suggestions.length)) { this.highlightOption = this.suggestions[nextItemIndex]; this.highlightOptionChanged = true; } } else { this.highlightOption = this.suggestions[0]; } event.preventDefault(); break; //up case 38: if (highlightItemIndex > 0) { let prevItemIndex = highlightItemIndex - 1; this.highlightOption = this.suggestions[prevItemIndex]; this.highlightOptionChanged = true; } event.preventDefault(); break; //enter case 13: if (this.highlightOption) { this.selectItem(this.highlightOption); this.hide(); } event.preventDefault(); break; //escape case 27: this.hide(); event.preventDefault(); break; //tab case 9: if (this.highlightOption) { this.selectItem(this.highlightOption); } this.hide(); break; } } else { if (event.which === 40 && this.suggestions) { this.search(event, event.target.value); } } if (this.multiple) { switch (event.which) { //backspace case 8: if (this.value && this.value.length && !this.multiInputEL.nativeElement.value) { this.value = [...this.value]; const removedValue = this.value.pop(); this.onModelChange(this.value); this.updateFilledState(); this.onUnselect.emit(removedValue); } break; } } this.inputKeyDown = true; } onKeyup(event) { this.onKeyUp.emit(event); } onInputFocus(event) { if (!this.itemClicked && this.completeOnFocus) { let queryValue = this.multiple ? this.multiInputEL.nativeElement.value : this.inputEL.nativeElement.value; this.search(event, queryValue); } this.focus = true; this.onFocus.emit(event); this.itemClicked = false; } onInputBlur(event) { this.focus = false; this.onModelTouched(); this.onBlur.emit(event); } onInputChange(event) { if (this.forceSelection) { let valid = false; let inputValue = event.target.value.trim(); if (this.suggestions) { for (let suggestion of this.suggestions) { let itemValue = this.field ? ObjectUtils.resolveFieldData(suggestion, this.field) : suggestion; if (itemValue && inputValue === itemValue.trim()) { valid = true; this.forceSelectionUpdateModelTimeout = setTimeout(() => { this.selectItem(suggestion, false); }, 250); break; } } } if (!valid) { if (this.multiple) { this.multiInputEL.nativeElement.value = ''; } else { this.value = null; this.inputEL.nativeElement.value = ''; } this.onClear.emit(event); this.onModelChange(this.value); } } } onInputPaste(event) { this.onKeydown(event); } isSelected(val) { let selected = false; if (this.value && this.value.length) { for (let i = 0; i < this.value.length; i++) { if (ObjectUtils.equals(this.value[i], val, this.dataKey)) { selected = true; break; } } } return selected; } findOptionIndex(option) { let index = -1; if (this.suggestions) { for (let i = 0; i < this.suggestions.length; i++) { if (ObjectUtils.equals(option, this.suggestions[i])) { index = i; break; } } } return index; } updateFilledState() { if (this.multiple) this.filled = (this.value && this.value.length) || (this.multiInputEL && this.multiInputEL.nativeElement && this.multiInputEL.nativeElement.value != ''); else this.filled = (this.inputFieldValue && this.inputFieldValue != '') || (this.inputEL && this.inputEL.nativeElement && this.inputEL.nativeElement.value != ''); ; } updateInputField() { let formattedValue = this.value ? (this.field ? ObjectUtils.resolveFieldData(this.value, this.field) || '' : this.value) : ''; this.inputFieldValue = formattedValue; if (this.inputEL && this.inputEL.nativeElement) { this.inputEL.nativeElement.value = formattedValue; } this.updateFilledState(); } bindDocumentClickListener() { if (!this.documentClickListener) { this.documentClickListener = this.renderer.listen('document', 'click', (event) => { if (event.which === 3) { return; } if (!this.inputClick && !this.isDropdownClick(event)) { this.hide(); } this.inputClick = false; this.cd.markForCheck(); }); } } isDropdownClick(event) { if (this.dropdown) { let target = event.target; return (target === this.dropdownButton.nativeElement || target.parentNode === this.dropdownButton.nativeElement); } else { return false; } } unbindDocumentClickListener() { if (this.documentClickListener) { this.documentClickListener(); this.documentClickListener = null; } } bindDocumentResizeListener() { this.documentResizeListener = this.onWindowResize.bind(this); window.addEventListener('resize', this.documentResizeListener); } unbindDocumentResizeListener() { if (this.documentResizeListener) { window.removeEventListener('resize', this.documentResizeListener); this.documentResizeListener = null; } } onWindowResize() { this.hide(); } onOverlayHide() { this.unbindDocumentClickListener(); this.unbindDocumentResizeListener(); this.overlay = null; this.onHide.emit(); } ngOnDestroy() { if (this.forceSelectionUpdateModelTimeout) { clearTimeout(this.forceSelectionUpdateModelTimeout); this.forceSelectionUpdateModelTimeout = null; } this.restoreOverlayAppend(); this.onOverlayHide(); } }; AutoComplete.ctorParameters = () => [ { type: ElementRef }, { type: Renderer2 }, { type: ChangeDetectorRef }, { type: IterableDiffers } ]; __decorate([ Input() ], AutoComplete.prototype, "minLength", void 0); __decorate([ Input() ], AutoComplete.prototype, "delay", void 0); __decorate([ Input() ], AutoComplete.prototype, "style", void 0); __decorate([ Input() ], AutoComplete.prototype, "panelStyle", void 0); __decorate([ Input() ], AutoComplete.prototype, "styleClass", void 0); __decorate([ Input() ], AutoComplete.prototype, "panelStyleClass", void 0); __decorate([ Input() ], AutoComplete.prototype, "inputStyle", void 0); __decorate([ Input() ], AutoComplete.prototype, "inputId", void 0); __decorate([ Input() ], AutoComplete.prototype, "inputStyleClass", void 0); __decorate([ Input() ], AutoComplete.prototype, "placeholder", void 0); __decorate([ Input() ], AutoComplete.prototype, "readonly", void 0); __decorate([ Input() ], AutoComplete.prototype, "disabled", void 0); __decorate([ Input() ], AutoComplete.prototype, "maxlength", void 0); __decorate([ Input() ], AutoComplete.prototype, "name", void 0); __decorate([ Input() ], AutoComplete.prototype, "required", void 0); __decorate([ Input() ], AutoComplete.prototype, "size", void 0); __decorate([ Input() ], AutoComplete.prototype, "appendTo", void 0); __decorate([ Input() ], AutoComplete.prototype, "autoHighlight", void 0); __decorate([ Input() ], AutoComplete.prototype, "forceSelection", void 0); __decorate([ Input() ], AutoComplete.prototype, "type", void 0); __decorate([ Input() ], AutoComplete.prototype, "autoZIndex", void 0); __decorate([ Input() ], AutoComplete.prototype, "baseZIndex", void 0); __decorate([ Input() ], AutoComplete.prototype, "ariaLabel", void 0); __decorate([ Input() ], AutoComplete.prototype, "ariaLabelledBy", void 0); __decorate([ Input() ], AutoComplete.prototype, "dropdownIcon", void 0); __decorate([ Input() ], AutoComplete.prototype, "unique", void 0); __decorate([ Input() ], AutoComplete.prototype, "completeOnFocus", void 0); __decorate([ Output() ], AutoComplete.prototype, "completeMethod", void 0); __decorate([ Output() ], AutoComplete.prototype, "onSelect", void 0); __decorate([ Output() ], AutoComplete.prototype, "onUnselect", void 0); __decorate([ Output() ], AutoComplete.prototype, "onFocus", void 0); __decorate([ Output() ], AutoComplete.prototype, "onBlur", void 0); __decorate([ Output() ], AutoComplete.prototype, "onDropdownClick", void 0); __decorate([ Output() ], AutoComplete.prototype, "onClear", void 0); __decorate([ Output() ], AutoComplete.prototype, "onKeyUp", void 0); __decorate([ Output() ], AutoComplete.prototype, "onShow", void 0); __decorate([ Output() ], AutoComplete.prototype, "onHide", void 0); __decorate([ Input() ], AutoComplete.prototype, "field", void 0); __decorate([ Input() ], AutoComplete.prototype, "scrollHeight", void 0); __decorate([ Input() ], AutoComplete.prototype, "dropdown", void 0); __decorate([ Input() ], AutoComplete.prototype, "dropdownMode", void 0); __decorate([ Input() ], AutoComplete.prototype, "multiple", void 0); __decorate([ Input() ], AutoComplete.prototype, "tabindex", void 0); __decorate([ Input() ], AutoComplete.prototype, "dataKey", void 0); __decorate([ Input() ], AutoComplete.prototype, "emptyMessage", void 0); __decorate([ Input() ], AutoComplete.prototype, "showTransitionOptions", void 0); __decorate([ Input() ], AutoComplete.prototype, "hideTransitionOptions", void 0); __decorate([ Input() ], AutoComplete.prototype, "autofocus", void 0); __decorate([ Input() ], AutoComplete.prototype, "autocomplete", void 0); __decorate([ ViewChild('in') ], AutoComplete.prototype, "inputEL", void 0); __decorate([ ViewChild('multiIn') ], AutoComplete.prototype, "multiInputEL", void 0); __decorate([ ViewChild('multiContainer') ], AutoComplete.prototype, "multiContainerEL", void 0); __decorate([ ViewChild('ddBtn') ], AutoComplete.prototype, "dropdownButton", void 0); __decorate([ ContentChildren(PrimeTemplate) ], AutoComplete.prototype, "templates", void 0); __decorate([ Input() ], AutoComplete.prototype, "suggestions", null); AutoComplete = __decorate([ Component({ selector: 'p-autoComplete', template: ` <span [ngClass]="{'ui-autocomplete ui-widget':true,'ui-autocomplete-dd':dropdown,'ui-autocomplete-multiple':multiple}" [ngStyle]="style" [class]="styleClass"> <input *ngIf="!multiple" #in [attr.type]="type" [attr.id]="inputId" [ngStyle]="inputStyle" [class]="inputStyleClass" [autocomplete]="autocomplete" [attr.required]="required" [attr.name]="name" [ngClass]="'ui-inputtext ui-widget ui-state-default ui-corner-all ui-autocomplete-input'" [value]="inputFieldValue" aria-autocomplete="list" [attr.aria-controls]="listId" role="searchbox" [attr.aria-expanded]="overlayVisible" aria-haspopup="true" [attr.aria-activedescendant]="'p-highlighted-option'" (click)="onInputClick($event)" (input)="onInput($event)" (keydown)="onKeydown($event)" (keyup)="onKeyup($event)" [attr.autofocus]="autofocus" (focus)="onInputFocus($event)" (blur)="onInputBlur($event)" (change)="onInputChange($event)" (paste)="onInputPaste($event)" [attr.placeholder]="placeholder" [attr.size]="size" [attr.maxlength]="maxlength" [attr.tabindex]="tabindex" [readonly]="readonly" [disabled]="disabled" [attr.aria-label]="ariaLabel" [attr.aria-labelledby]="ariaLabelledBy" [attr.aria-required]="required" ><ul *ngIf="multiple" #multiContainer class="ui-autocomplete-multiple-container ui-widget ui-inputtext ui-state-default ui-corner-all" [ngClass]="{'ui-state-disabled':disabled,'ui-state-focus':focus}" (click)="multiIn.focus()"> <li #token *ngFor="let val of value" class="ui-autocomplete-token ui-state-highlight ui-corner-all"> <span class="ui-autocomplete-token-icon pi pi-fw pi-times" (click)="removeItem(token)" *ngIf="!disabled"></span> <span *ngIf="!selectedItemTemplate" class="ui-autocomplete-token-label">{{resolveFieldData(val)}}</span> <ng-container *ngTemplateOutlet="selectedItemTemplate; context: {$implicit: val}"></ng-container> </li> <li class="ui-autocomplete-input-token"> <input #multiIn [attr.type]="type" [attr.id]="inputId" [disabled]="disabled" [attr.placeholder]="(value&&value.length ? null : placeholder)" [attr.tabindex]="tabindex" [attr.maxlength]="maxlength" (input)="onInput($event)" (click)="onInputClick($event)" (keydown)="onKeydown($event)" [readonly]="readonly" (keyup)="onKeyup($event)" [attr.autofocus]="autofocus" (focus)="onInputFocus($event)" (blur)="onInputBlur($event)" (change)="onInputChange($event)" (paste)="onInputPaste($event)" [autocomplete]="autocomplete" [ngStyle]="inputStyle" [class]="inputStyleClass" [attr.aria-label]="ariaLabel" [attr.aria-labelledby]="ariaLabelledBy" [attr.aria-required]="required" aria-autocomplete="list" [attr.aria-controls]="listId" role="searchbox" [attr.aria-expanded]="overlayVisible" aria-haspopup="true" [attr.aria-activedescendant]="'p-highlighted-option'"> </li> </ul> <i *ngIf="loading" class="ui-autocomplete-loader pi pi-spinner pi-spin"></i><button #ddBtn type="button" pButton [icon]="dropdownIcon" class="ui-autocomplete-dropdown" [disabled]="disabled" (click)="handleDropdownClick($event)" *ngIf="dropdown" [attr.tabindex]="tabindex"></button> <div #panel *ngIf="overlayVisible" [ngClass]="['ui-autocomplete-panel ui-widget ui-widget-content ui-corner-all ui-shadow']" [style.max-height]="scrollHeight" [ngStyle]="panelStyle" [class]="panelStyleClass" [@overlayAnimation]="{value: 'visible', params: {showTransitionParams: showTransitionOptions, hideTransitionParams: hideTransitionOptions}}" (@overlayAnimation.start)="onOverlayAnimationStart($event)" (@overlayAnimation.done)="onOverlayAnimationDone($event)" > <ul role="listbox" [attr.id]="listId" class="ui-autocomplete-items ui-autocomplete-list ui-widget-content ui-widget ui-corner-all ui-helper-reset"> <li role="option" *ngFor="let option of suggestions; let idx = index" [ngClass]="{'ui-autocomplete-list-item ui-corner-all':true,'ui-state-highlight':(highlightOption==option)}" (mouseenter)="highlightOption=option" (mouseleave)="highlightOption=null" [id]="highlightOption == option ? 'p-highlighted-option':''" (click)="selectItem(option)"> <span *ngIf="!itemTemplate">{{resolveFieldData(option)}}</span> <ng-container *ngTemplateOutlet="itemTemplate; context: {$implicit: option, index: idx}"></ng-container> </li> <li *ngIf="noResults && emptyMessage" class="ui-autocomplete-emptymessage ui-autocomplete-list-item ui-corner-all">{{emptyMessage}}</li> </ul> </div> </span> `, animations: [ trigger('overlayAnimation', [ state('void', style({ transform: 'translateY(5%)', opacity: 0 })), state('visible', style({ transform: 'translateY(0)', opacity: 1 })), transition('void => visible', animate('{{showTransitionParams}}')), transition('visible => void', animate('{{hideTransitionParams}}')) ]) ], host: { '[class.ui-inputwrapper-filled]': 'filled', '[class.ui-inputwrapper-focus]': 'focus && !disabled' }, providers: [AUTOCOMPLETE_VALUE_ACCESSOR], changeDetection: ChangeDetectionStrategy.Default }) ], AutoComplete); let AutoCompleteModule = class AutoCompleteModule { }; AutoCompleteModule = __decorate([ NgModule({ imports: [CommonModule, InputTextModule, ButtonModule, SharedModule], exports: [AutoComplete, SharedModule], declarations: [AutoComplete] }) ], AutoCompleteModule); /** * Generated bundle index. Do not edit. */ export { AUTOCOMPLETE_VALUE_ACCESSOR, AutoComplete, AutoCompleteModule }; //# sourceMappingURL=primeng-autocomplete.js.map