UNPKG

40.6 kBJavaScriptView Raw
1import { CdkVirtualScrollViewport, ScrollingModule } from '@angular/cdk/scrolling';
2import { forwardRef, EventEmitter, Component, Input, Output, ChangeDetectionStrategy, ViewEncapsulation, ElementRef, Renderer2, ChangeDetectorRef, NgZone, ViewChild, ContentChildren, NgModule } from '@angular/core';
3import { trigger, transition, style, animate } from '@angular/animations';
4import { CommonModule } from '@angular/common';
5import { PrimeTemplate, SharedModule } from 'primeng/api';
6import { DomHandler, ConnectedOverlayScrollHandler } from 'primeng/dom';
7import { ObjectUtils, FilterUtils } from 'primeng/utils';
8import { NG_VALUE_ACCESSOR } from '@angular/forms';
9import { TooltipModule } from 'primeng/tooltip';
10import { RippleModule } from 'primeng/ripple';
11
12const DROPDOWN_VALUE_ACCESSOR = {
13 provide: NG_VALUE_ACCESSOR,
14 useExisting: forwardRef(() => Dropdown),
15 multi: true
16};
17class DropdownItem {
18 constructor() {
19 this.onClick = new EventEmitter();
20 }
21 onOptionClick(event) {
22 this.onClick.emit({
23 originalEvent: event,
24 option: this.option
25 });
26 }
27}
28DropdownItem.decorators = [
29 { type: Component, args: [{
30 selector: 'p-dropdownItem',
31 template: `
32 <li (click)="onOptionClick($event)" role="option" pRipple
33 [attr.aria-label]="option.label" [attr.aria-selected]="selected"
34 [ngStyle]="{'height': itemSize + 'px'}"
35 [ngClass]="{'p-dropdown-item':true, 'p-highlight': selected, 'p-disabled':(option.disabled)}">
36 <span *ngIf="!template">{{option.label||'empty'}}</span>
37 <ng-container *ngTemplateOutlet="template; context: {$implicit: option}"></ng-container>
38 </li>
39 `
40 },] }
41];
42DropdownItem.propDecorators = {
43 option: [{ type: Input }],
44 selected: [{ type: Input }],
45 disabled: [{ type: Input }],
46 visible: [{ type: Input }],
47 itemSize: [{ type: Input }],
48 template: [{ type: Input }],
49 onClick: [{ type: Output }]
50};
51class Dropdown {
52 constructor(el, renderer, cd, zone) {
53 this.el = el;
54 this.renderer = renderer;
55 this.cd = cd;
56 this.zone = zone;
57 this.scrollHeight = '200px';
58 this.filterBy = 'label';
59 this.resetFilterOnHide = false;
60 this.dropdownIcon = 'pi pi-chevron-down';
61 this.autoDisplayFirst = true;
62 this.emptyFilterMessage = 'No results found';
63 this.autoZIndex = true;
64 this.baseZIndex = 0;
65 this.showTransitionOptions = '.12s cubic-bezier(0, 0, 0.2, 1)';
66 this.hideTransitionOptions = '.1s linear';
67 this.filterMatchMode = "contains";
68 this.tooltip = '';
69 this.tooltipPosition = 'right';
70 this.tooltipPositionStyle = 'absolute';
71 this.autofocusFilter = true;
72 this.onChange = new EventEmitter();
73 this.onFocus = new EventEmitter();
74 this.onBlur = new EventEmitter();
75 this.onClick = new EventEmitter();
76 this.onShow = new EventEmitter();
77 this.onHide = new EventEmitter();
78 this.onModelChange = () => { };
79 this.onModelTouched = () => { };
80 this.viewPortOffsetTop = 0;
81 }
82 get disabled() {
83 return this._disabled;
84 }
85 ;
86 set disabled(_disabled) {
87 if (_disabled)
88 this.focused = false;
89 this._disabled = _disabled;
90 if (!this.cd.destroyed) {
91 this.cd.detectChanges();
92 }
93 }
94 ngAfterContentInit() {
95 this.templates.forEach((item) => {
96 switch (item.getType()) {
97 case 'item':
98 this.itemTemplate = item.template;
99 break;
100 case 'selectedItem':
101 this.selectedItemTemplate = item.template;
102 break;
103 case 'group':
104 this.groupTemplate = item.template;
105 break;
106 default:
107 this.itemTemplate = item.template;
108 break;
109 }
110 });
111 }
112 ngOnInit() {
113 this.optionsToDisplay = this.options;
114 this.updateSelectedOption(null);
115 }
116 get options() {
117 return this._options;
118 }
119 set options(val) {
120 let opts = this.optionLabel ? ObjectUtils.generateSelectItems(val, this.optionLabel) : val;
121 this._options = opts;
122 this.optionsToDisplay = this._options;
123 this.updateSelectedOption(this.value);
124 this.optionsChanged = true;
125 this.updateFilledState();
126 if (this.filterValue && this.filterValue.length) {
127 this.activateFilter();
128 }
129 }
130 ngAfterViewInit() {
131 if (this.editable) {
132 this.updateEditableLabel();
133 }
134 }
135 get label() {
136 return (this.selectedOption ? this.selectedOption.label : null);
137 }
138 updateEditableLabel() {
139 if (this.editableInputViewChild && this.editableInputViewChild.nativeElement) {
140 this.editableInputViewChild.nativeElement.value = (this.selectedOption ? this.selectedOption.label : this.value || '');
141 }
142 }
143 onItemClick(event) {
144 const option = event.option;
145 if (!option.disabled) {
146 this.selectItem(event, option);
147 this.accessibleViewChild.nativeElement.focus();
148 }
149 setTimeout(() => {
150 this.hide(event);
151 }, 150);
152 }
153 selectItem(event, option) {
154 if (this.selectedOption != option) {
155 this.selectedOption = option;
156 this.value = option.value;
157 this.filled = true;
158 this.onModelChange(this.value);
159 this.updateEditableLabel();
160 this.onChange.emit({
161 originalEvent: event.originalEvent,
162 value: this.value
163 });
164 if (this.virtualScroll) {
165 setTimeout(() => {
166 this.viewPortOffsetTop = this.viewPort ? this.viewPort.measureScrollOffset() : 0;
167 }, 1);
168 }
169 }
170 }
171 ngAfterViewChecked() {
172 if (this.optionsChanged && this.overlayVisible) {
173 this.optionsChanged = false;
174 if (this.virtualScroll) {
175 this.updateVirtualScrollSelectedIndex(true);
176 }
177 this.zone.runOutsideAngular(() => {
178 setTimeout(() => {
179 this.alignOverlay();
180 }, 1);
181 });
182 }
183 if (this.selectedOptionUpdated && this.itemsWrapper) {
184 if (this.virtualScroll && this.viewPort) {
185 let range = this.viewPort.getRenderedRange();
186 this.updateVirtualScrollSelectedIndex(false);
187 if (range.start > this.virtualScrollSelectedIndex || range.end < this.virtualScrollSelectedIndex) {
188 this.viewPort.scrollToIndex(this.virtualScrollSelectedIndex);
189 }
190 }
191 let selectedItem = DomHandler.findSingle(this.overlay, 'li.p-highlight');
192 if (selectedItem) {
193 DomHandler.scrollInView(this.itemsWrapper, DomHandler.findSingle(this.overlay, 'li.p-highlight'));
194 }
195 this.selectedOptionUpdated = false;
196 }
197 }
198 writeValue(value) {
199 if (this.filter) {
200 this.resetFilter();
201 }
202 this.value = value;
203 this.updateSelectedOption(value);
204 this.updateEditableLabel();
205 this.updateFilledState();
206 this.cd.markForCheck();
207 }
208 resetFilter() {
209 this.filterValue = null;
210 if (this.filterViewChild && this.filterViewChild.nativeElement) {
211 this.filterViewChild.nativeElement.value = '';
212 }
213 this.optionsToDisplay = this.options;
214 }
215 updateSelectedOption(val) {
216 this.selectedOption = this.findOption(val, this.optionsToDisplay);
217 if (this.autoDisplayFirst && !this.placeholder && !this.selectedOption && this.optionsToDisplay && this.optionsToDisplay.length && !this.editable) {
218 this.selectedOption = this.optionsToDisplay[0];
219 }
220 this.selectedOptionUpdated = true;
221 }
222 registerOnChange(fn) {
223 this.onModelChange = fn;
224 }
225 registerOnTouched(fn) {
226 this.onModelTouched = fn;
227 }
228 setDisabledState(val) {
229 this.disabled = val;
230 this.cd.markForCheck();
231 }
232 onMouseclick(event) {
233 if (this.disabled || this.readonly || this.isInputClick(event)) {
234 return;
235 }
236 this.onClick.emit(event);
237 this.accessibleViewChild.nativeElement.focus();
238 if (this.overlayVisible)
239 this.hide(event);
240 else
241 this.show();
242 this.cd.detectChanges();
243 }
244 isInputClick(event) {
245 return DomHandler.hasClass(event.target, 'p-dropdown-clear-icon') ||
246 event.target.isSameNode(this.accessibleViewChild.nativeElement) ||
247 (this.editableInputViewChild && event.target.isSameNode(this.editableInputViewChild.nativeElement));
248 }
249 isOutsideClicked(event) {
250 return !(this.el.nativeElement.isSameNode(event.target) || this.el.nativeElement.contains(event.target) || (this.overlay && this.overlay.contains(event.target)));
251 }
252 onEditableInputClick() {
253 this.bindDocumentClickListener();
254 }
255 onEditableInputFocus(event) {
256 this.focused = true;
257 this.hide(event);
258 this.onFocus.emit(event);
259 }
260 onEditableInputChange(event) {
261 this.value = event.target.value;
262 this.updateSelectedOption(this.value);
263 this.onModelChange(this.value);
264 this.onChange.emit({
265 originalEvent: event,
266 value: this.value
267 });
268 }
269 show() {
270 this.overlayVisible = true;
271 }
272 onOverlayAnimationStart(event) {
273 switch (event.toState) {
274 case 'visible':
275 this.overlay = event.element;
276 let itemsWrapperSelector = this.virtualScroll ? '.cdk-virtual-scroll-viewport' : '.p-dropdown-items-wrapper';
277 this.itemsWrapper = DomHandler.findSingle(this.overlay, itemsWrapperSelector);
278 this.appendOverlay();
279 if (this.autoZIndex) {
280 this.overlay.style.zIndex = String(this.baseZIndex + (++DomHandler.zindex));
281 }
282 this.alignOverlay();
283 this.bindDocumentClickListener();
284 this.bindDocumentResizeListener();
285 this.bindScrollListener();
286 if (this.options && this.options.length) {
287 if (!this.virtualScroll) {
288 let selectedListItem = DomHandler.findSingle(this.itemsWrapper, '.p-dropdown-item.p-highlight');
289 if (selectedListItem) {
290 DomHandler.scrollInView(this.itemsWrapper, selectedListItem);
291 }
292 }
293 }
294 if (this.filterViewChild && this.filterViewChild.nativeElement) {
295 this.preventModelTouched = true;
296 if (this.autofocusFilter) {
297 this.filterViewChild.nativeElement.focus();
298 }
299 }
300 this.onShow.emit(event);
301 break;
302 case 'void':
303 this.onOverlayHide();
304 break;
305 }
306 }
307 scrollToSelectedVirtualScrollElement() {
308 if (!this.virtualAutoScrolled) {
309 if (this.viewPortOffsetTop) {
310 this.viewPort.scrollToOffset(this.viewPortOffsetTop);
311 }
312 else if (this.virtualScrollSelectedIndex > -1) {
313 this.viewPort.scrollToIndex(this.virtualScrollSelectedIndex);
314 }
315 }
316 this.virtualAutoScrolled = true;
317 }
318 updateVirtualScrollSelectedIndex(resetOffset) {
319 if (this.selectedOption && this.optionsToDisplay && this.optionsToDisplay.length) {
320 if (resetOffset) {
321 this.viewPortOffsetTop = 0;
322 }
323 this.virtualScrollSelectedIndex = this.findOptionIndex(this.selectedOption.value, this.optionsToDisplay);
324 }
325 }
326 appendOverlay() {
327 if (this.appendTo) {
328 if (this.appendTo === 'body')
329 document.body.appendChild(this.overlay);
330 else
331 DomHandler.appendChild(this.overlay, this.appendTo);
332 if (!this.overlay.style.minWidth) {
333 this.overlay.style.minWidth = DomHandler.getWidth(this.containerViewChild.nativeElement) + 'px';
334 }
335 }
336 }
337 restoreOverlayAppend() {
338 if (this.overlay && this.appendTo) {
339 this.el.nativeElement.appendChild(this.overlay);
340 }
341 }
342 hide(event) {
343 this.overlayVisible = false;
344 if (this.filter && this.resetFilterOnHide) {
345 this.resetFilter();
346 }
347 if (this.virtualScroll) {
348 this.virtualAutoScrolled = false;
349 }
350 this.cd.markForCheck();
351 this.onHide.emit(event);
352 }
353 alignOverlay() {
354 if (this.overlay) {
355 if (this.appendTo)
356 DomHandler.absolutePosition(this.overlay, this.containerViewChild.nativeElement);
357 else
358 DomHandler.relativePosition(this.overlay, this.containerViewChild.nativeElement);
359 }
360 }
361 onInputFocus(event) {
362 this.focused = true;
363 this.onFocus.emit(event);
364 }
365 onInputBlur(event) {
366 this.focused = false;
367 this.onBlur.emit(event);
368 if (!this.preventModelTouched) {
369 this.onModelTouched();
370 }
371 this.preventModelTouched = false;
372 }
373 findPrevEnabledOption(index) {
374 let prevEnabledOption;
375 if (this.optionsToDisplay && this.optionsToDisplay.length) {
376 for (let i = (index - 1); 0 <= i; i--) {
377 let option = this.optionsToDisplay[i];
378 if (option.disabled) {
379 continue;
380 }
381 else {
382 prevEnabledOption = option;
383 break;
384 }
385 }
386 if (!prevEnabledOption) {
387 for (let i = this.optionsToDisplay.length - 1; i >= index; i--) {
388 let option = this.optionsToDisplay[i];
389 if (option.disabled) {
390 continue;
391 }
392 else {
393 prevEnabledOption = option;
394 break;
395 }
396 }
397 }
398 }
399 return prevEnabledOption;
400 }
401 findNextEnabledOption(index) {
402 let nextEnabledOption;
403 if (this.optionsToDisplay && this.optionsToDisplay.length) {
404 for (let i = (index + 1); index < (this.optionsToDisplay.length - 1); i++) {
405 let option = this.optionsToDisplay[i];
406 if (option.disabled) {
407 continue;
408 }
409 else {
410 nextEnabledOption = option;
411 break;
412 }
413 }
414 if (!nextEnabledOption) {
415 for (let i = 0; i < index; i++) {
416 let option = this.optionsToDisplay[i];
417 if (option.disabled) {
418 continue;
419 }
420 else {
421 nextEnabledOption = option;
422 break;
423 }
424 }
425 }
426 }
427 return nextEnabledOption;
428 }
429 onKeydown(event, search) {
430 if (this.readonly || !this.optionsToDisplay || this.optionsToDisplay.length === null) {
431 return;
432 }
433 switch (event.which) {
434 //down
435 case 40:
436 if (!this.overlayVisible && event.altKey) {
437 this.show();
438 }
439 else {
440 if (this.group) {
441 let selectedItemIndex = this.selectedOption ? this.findOptionGroupIndex(this.selectedOption.value, this.optionsToDisplay) : -1;
442 if (selectedItemIndex !== -1) {
443 let nextItemIndex = selectedItemIndex.itemIndex + 1;
444 if (nextItemIndex < (this.optionsToDisplay[selectedItemIndex.groupIndex].items.length)) {
445 this.selectItem(event, this.optionsToDisplay[selectedItemIndex.groupIndex].items[nextItemIndex]);
446 this.selectedOptionUpdated = true;
447 }
448 else if (this.optionsToDisplay[selectedItemIndex.groupIndex + 1]) {
449 this.selectItem(event, this.optionsToDisplay[selectedItemIndex.groupIndex + 1].items[0]);
450 this.selectedOptionUpdated = true;
451 }
452 }
453 else {
454 this.selectItem(event, this.optionsToDisplay[0].items[0]);
455 }
456 }
457 else {
458 let selectedItemIndex = this.selectedOption ? this.findOptionIndex(this.selectedOption.value, this.optionsToDisplay) : -1;
459 let nextEnabledOption = this.findNextEnabledOption(selectedItemIndex);
460 if (nextEnabledOption) {
461 this.selectItem(event, nextEnabledOption);
462 this.selectedOptionUpdated = true;
463 }
464 }
465 }
466 event.preventDefault();
467 break;
468 //up
469 case 38:
470 if (this.group) {
471 let selectedItemIndex = this.selectedOption ? this.findOptionGroupIndex(this.selectedOption.value, this.optionsToDisplay) : -1;
472 if (selectedItemIndex !== -1) {
473 let prevItemIndex = selectedItemIndex.itemIndex - 1;
474 if (prevItemIndex >= 0) {
475 this.selectItem(event, this.optionsToDisplay[selectedItemIndex.groupIndex].items[prevItemIndex]);
476 this.selectedOptionUpdated = true;
477 }
478 else if (prevItemIndex < 0) {
479 let prevGroup = this.optionsToDisplay[selectedItemIndex.groupIndex - 1];
480 if (prevGroup) {
481 this.selectItem(event, prevGroup.items[prevGroup.items.length - 1]);
482 this.selectedOptionUpdated = true;
483 }
484 }
485 }
486 }
487 else {
488 let selectedItemIndex = this.selectedOption ? this.findOptionIndex(this.selectedOption.value, this.optionsToDisplay) : -1;
489 let prevEnabledOption = this.findPrevEnabledOption(selectedItemIndex);
490 if (prevEnabledOption) {
491 this.selectItem(event, prevEnabledOption);
492 this.selectedOptionUpdated = true;
493 }
494 }
495 event.preventDefault();
496 break;
497 //space
498 case 32:
499 case 32:
500 if (!this.overlayVisible) {
501 this.show();
502 event.preventDefault();
503 }
504 break;
505 //enter
506 case 13:
507 if (!this.filter || (this.optionsToDisplay && this.optionsToDisplay.length > 0)) {
508 this.hide(event);
509 }
510 event.preventDefault();
511 break;
512 //escape and tab
513 case 27:
514 case 9:
515 this.hide(event);
516 break;
517 //search item based on keyboard input
518 default:
519 if (search) {
520 this.search(event);
521 }
522 break;
523 }
524 }
525 search(event) {
526 if (this.searchTimeout) {
527 clearTimeout(this.searchTimeout);
528 }
529 const char = event.key;
530 this.previousSearchChar = this.currentSearchChar;
531 this.currentSearchChar = char;
532 if (this.previousSearchChar === this.currentSearchChar)
533 this.searchValue = this.currentSearchChar;
534 else
535 this.searchValue = this.searchValue ? this.searchValue + char : char;
536 let newOption;
537 if (this.group) {
538 let searchIndex = this.selectedOption ? this.findOptionGroupIndex(this.selectedOption.value, this.optionsToDisplay) : { groupIndex: 0, itemIndex: 0 };
539 newOption = this.searchOptionWithinGroup(searchIndex);
540 }
541 else {
542 let searchIndex = this.selectedOption ? this.findOptionIndex(this.selectedOption.value, this.optionsToDisplay) : -1;
543 newOption = this.searchOption(++searchIndex);
544 }
545 if (newOption && !newOption.disabled) {
546 this.selectItem(event, newOption);
547 this.selectedOptionUpdated = true;
548 }
549 this.searchTimeout = setTimeout(() => {
550 this.searchValue = null;
551 }, 250);
552 }
553 searchOption(index) {
554 let option;
555 if (this.searchValue) {
556 option = this.searchOptionInRange(index, this.optionsToDisplay.length);
557 if (!option) {
558 option = this.searchOptionInRange(0, index);
559 }
560 }
561 return option;
562 }
563 searchOptionInRange(start, end) {
564 for (let i = start; i < end; i++) {
565 let opt = this.optionsToDisplay[i];
566 if (opt.label.toLocaleLowerCase(this.filterLocale).startsWith(this.searchValue.toLocaleLowerCase(this.filterLocale)) && !opt.disabled) {
567 return opt;
568 }
569 }
570 return null;
571 }
572 searchOptionWithinGroup(index) {
573 let option;
574 if (this.searchValue) {
575 for (let i = index.groupIndex; i < this.optionsToDisplay.length; i++) {
576 for (let j = (index.groupIndex === i) ? (index.itemIndex + 1) : 0; j < this.optionsToDisplay[i].items.length; j++) {
577 let opt = this.optionsToDisplay[i].items[j];
578 if (opt.label.toLocaleLowerCase(this.filterLocale).startsWith(this.searchValue.toLocaleLowerCase(this.filterLocale)) && !opt.disabled) {
579 return opt;
580 }
581 }
582 }
583 if (!option) {
584 for (let i = 0; i <= index.groupIndex; i++) {
585 for (let j = 0; j < ((index.groupIndex === i) ? index.itemIndex : this.optionsToDisplay[i].items.length); j++) {
586 let opt = this.optionsToDisplay[i].items[j];
587 if (opt.label.toLocaleLowerCase(this.filterLocale).startsWith(this.searchValue.toLocaleLowerCase(this.filterLocale)) && !opt.disabled) {
588 return opt;
589 }
590 }
591 }
592 }
593 }
594 return null;
595 }
596 findOptionIndex(val, opts) {
597 let index = -1;
598 if (opts) {
599 for (let i = 0; i < opts.length; i++) {
600 if ((val == null && opts[i].value == null) || ObjectUtils.equals(val, opts[i].value, this.dataKey)) {
601 index = i;
602 break;
603 }
604 }
605 }
606 return index;
607 }
608 findOptionGroupIndex(val, opts) {
609 let groupIndex, itemIndex;
610 if (opts) {
611 for (let i = 0; i < opts.length; i++) {
612 groupIndex = i;
613 itemIndex = this.findOptionIndex(val, opts[i].items);
614 if (itemIndex !== -1) {
615 break;
616 }
617 }
618 }
619 if (itemIndex !== -1) {
620 return { groupIndex: groupIndex, itemIndex: itemIndex };
621 }
622 else {
623 return -1;
624 }
625 }
626 findOption(val, opts, inGroup) {
627 if (this.group && !inGroup) {
628 let opt;
629 if (opts && opts.length) {
630 for (let optgroup of opts) {
631 opt = this.findOption(val, optgroup.items, true);
632 if (opt) {
633 break;
634 }
635 }
636 }
637 return opt;
638 }
639 else {
640 let index = this.findOptionIndex(val, opts);
641 return (index != -1) ? opts[index] : null;
642 }
643 }
644 onFilter(event) {
645 let inputValue = event.target.value;
646 if (inputValue && inputValue.length) {
647 this.filterValue = inputValue;
648 this.activateFilter();
649 }
650 else {
651 this.filterValue = null;
652 this.optionsToDisplay = this.options;
653 }
654 this.optionsChanged = true;
655 }
656 activateFilter() {
657 let searchFields = this.filterBy.split(',');
658 if (this.options && this.options.length) {
659 if (this.group) {
660 let filteredGroups = [];
661 for (let optgroup of this.options) {
662 let filteredSubOptions = FilterUtils.filter(optgroup.items, searchFields, this.filterValue, this.filterMatchMode, this.filterLocale);
663 if (filteredSubOptions && filteredSubOptions.length) {
664 filteredGroups.push({
665 label: optgroup.label,
666 value: optgroup.value,
667 items: filteredSubOptions
668 });
669 }
670 }
671 this.optionsToDisplay = filteredGroups;
672 }
673 else {
674 this.optionsToDisplay = FilterUtils.filter(this.options, searchFields, this.filterValue, this.filterMatchMode, this.filterLocale);
675 }
676 this.optionsChanged = true;
677 }
678 }
679 applyFocus() {
680 if (this.editable)
681 DomHandler.findSingle(this.el.nativeElement, '.p-dropdown-label.p-inputtext').focus();
682 else
683 DomHandler.findSingle(this.el.nativeElement, 'input[readonly]').focus();
684 }
685 focus() {
686 this.applyFocus();
687 }
688 bindDocumentClickListener() {
689 if (!this.documentClickListener) {
690 const documentTarget = this.el ? this.el.nativeElement.ownerDocument : 'document';
691 this.documentClickListener = this.renderer.listen(documentTarget, 'click', (event) => {
692 if (this.isOutsideClicked(event)) {
693 this.hide(event);
694 this.unbindDocumentClickListener();
695 }
696 this.cd.markForCheck();
697 });
698 }
699 }
700 unbindDocumentClickListener() {
701 if (this.documentClickListener) {
702 this.documentClickListener();
703 this.documentClickListener = null;
704 }
705 }
706 bindDocumentResizeListener() {
707 this.documentResizeListener = this.onWindowResize.bind(this);
708 window.addEventListener('resize', this.documentResizeListener);
709 }
710 unbindDocumentResizeListener() {
711 if (this.documentResizeListener) {
712 window.removeEventListener('resize', this.documentResizeListener);
713 this.documentResizeListener = null;
714 }
715 }
716 onWindowResize() {
717 if (!DomHandler.isAndroid()) {
718 this.hide(event);
719 }
720 }
721 bindScrollListener() {
722 if (!this.scrollHandler) {
723 this.scrollHandler = new ConnectedOverlayScrollHandler(this.containerViewChild.nativeElement, (event) => {
724 if (this.overlayVisible) {
725 this.hide(event);
726 }
727 });
728 }
729 this.scrollHandler.bindScrollListener();
730 }
731 unbindScrollListener() {
732 if (this.scrollHandler) {
733 this.scrollHandler.unbindScrollListener();
734 }
735 }
736 updateFilledState() {
737 this.filled = (this.selectedOption != null);
738 }
739 clear(event) {
740 this.value = null;
741 this.onModelChange(this.value);
742 this.onChange.emit({
743 originalEvent: event,
744 value: this.value
745 });
746 this.updateSelectedOption(this.value);
747 this.updateEditableLabel();
748 this.updateFilledState();
749 }
750 onOverlayHide() {
751 this.unbindDocumentClickListener();
752 this.unbindDocumentResizeListener();
753 this.unbindScrollListener();
754 this.overlay = null;
755 this.itemsWrapper = null;
756 this.onModelTouched();
757 }
758 ngOnDestroy() {
759 if (this.scrollHandler) {
760 this.scrollHandler.destroy();
761 this.scrollHandler = null;
762 }
763 this.restoreOverlayAppend();
764 this.onOverlayHide();
765 }
766}
767Dropdown.decorators = [
768 { type: Component, args: [{
769 selector: 'p-dropdown',
770 template: `
771 <div #container [ngClass]="{'p-dropdown p-component':true,
772 'p-disabled':disabled, 'p-dropdown-open':overlayVisible, 'p-focus':focused, 'p-dropdown-clearable': showClear && !disabled}"
773 (click)="onMouseclick($event)" [ngStyle]="style" [class]="styleClass">
774 <div class="p-hidden-accessible">
775 <input #in [attr.id]="inputId" type="text" [attr.aria-label]="selectedOption ? selectedOption.label : ' '" readonly (focus)="onInputFocus($event)" aria-haspopup="listbox"
776 aria-haspopup="listbox" [attr.aria-expanded]="overlayVisible" [attr.aria-labelledby]="ariaLabelledBy" (blur)="onInputBlur($event)" (keydown)="onKeydown($event, true)"
777 [disabled]="disabled" [attr.tabindex]="tabindex" [attr.autofocus]="autofocus" role="listbox">
778 </div>
779 <span [ngClass]="{'p-dropdown-label p-inputtext':true,'p-dropdown-label-empty':(label == null || label.length === 0)}" *ngIf="!editable && (label != null)" [pTooltip]="tooltip" [tooltipPosition]="tooltipPosition" [positionStyle]="tooltipPositionStyle" [tooltipStyleClass]="tooltipStyleClass">
780 <ng-container *ngIf="!selectedItemTemplate">{{label||'empty'}}</ng-container>
781 <ng-container *ngTemplateOutlet="selectedItemTemplate; context: {$implicit: selectedOption}"></ng-container>
782 </span>
783 <span [ngClass]="{'p-dropdown-label p-inputtext p-placeholder':true,'p-dropdown-label-empty': (placeholder == null || placeholder.length === 0)}" *ngIf="!editable && (label == null)">{{placeholder||'empty'}}</span>
784 <input #editableInput type="text" [attr.maxlength]="maxlength" [attr.aria-label]="selectedOption ? selectedOption.label : ' '" class="p-dropdown-label p-inputtext" *ngIf="editable" [disabled]="disabled" [attr.placeholder]="placeholder"
785 aria-haspopup="listbox" [attr.aria-expanded]="overlayVisible" (click)="onEditableInputClick()" (input)="onEditableInputChange($event)" (focus)="onEditableInputFocus($event)" (blur)="onInputBlur($event)">
786 <i class="p-dropdown-clear-icon pi pi-times" (click)="clear($event)" *ngIf="value != null && showClear && !disabled"></i>
787 <div class="p-dropdown-trigger" role="button" aria-haspopup="listbox" [attr.aria-expanded]="overlayVisible">
788 <span class="p-dropdown-trigger-icon" [ngClass]="dropdownIcon"></span>
789 </div>
790 <div *ngIf="overlayVisible" [ngClass]="'p-dropdown-panel p-component'" [@overlayAnimation]="{value: 'visible', params: {showTransitionParams: showTransitionOptions, hideTransitionParams: hideTransitionOptions}}" (@overlayAnimation.start)="onOverlayAnimationStart($event)" [ngStyle]="panelStyle" [class]="panelStyleClass">
791 <div class="p-dropdown-header" *ngIf="filter" >
792 <div class="p-dropdown-filter-container" (click)="$event.stopPropagation()">
793 <input #filter type="text" autocomplete="off" [value]="filterValue||''" class="p-dropdown-filter p-inputtext p-component" [attr.placeholder]="filterPlaceholder"
794 (keydown.enter)="$event.preventDefault()" (keydown)="onKeydown($event, false)" (input)="onFilter($event)" [attr.aria-label]="ariaFilterLabel">
795 <span class="p-dropdown-filter-icon pi pi-search"></span>
796 </div>
797 </div>
798 <div class="p-dropdown-items-wrapper" [style.max-height]="virtualScroll ? 'auto' : (scrollHeight||'auto')">
799 <ul class="p-dropdown-items" role="listbox">
800 <ng-container *ngIf="group">
801 <ng-template ngFor let-optgroup [ngForOf]="optionsToDisplay">
802 <li class="p-dropdown-item-group">
803 <span *ngIf="!groupTemplate">{{optgroup.label||'empty'}}</span>
804 <ng-container *ngTemplateOutlet="groupTemplate; context: {$implicit: optgroup}"></ng-container>
805 </li>
806 <ng-container *ngTemplateOutlet="itemslist; context: {$implicit: optgroup.items, selectedOption: selectedOption}"></ng-container>
807 </ng-template>
808 </ng-container>
809 <ng-container *ngIf="!group">
810 <ng-container *ngTemplateOutlet="itemslist; context: {$implicit: optionsToDisplay, selectedOption: selectedOption}"></ng-container>
811 </ng-container>
812 <ng-template #itemslist let-options let-selectedOption="selectedOption">
813 <ng-container *ngIf="!virtualScroll; else virtualScrollList">
814 <ng-template ngFor let-option let-i="index" [ngForOf]="options">
815 <p-dropdownItem [option]="option" [selected]="selectedOption == option"
816 (onClick)="onItemClick($event)"
817 [template]="itemTemplate"></p-dropdownItem>
818 </ng-template>
819 </ng-container>
820 <ng-template #virtualScrollList>
821 <cdk-virtual-scroll-viewport (scrolledIndexChange)="scrollToSelectedVirtualScrollElement()" #viewport [ngStyle]="{'height': scrollHeight}" [itemSize]="itemSize" *ngIf="virtualScroll && optionsToDisplay && optionsToDisplay.length">
822 <ng-container *cdkVirtualFor="let option of options; let i = index; let c = count; let f = first; let l = last; let e = even; let o = odd">
823 <p-dropdownItem [option]="option" [selected]="selectedOption == option"
824 (onClick)="onItemClick($event)"
825 [template]="itemTemplate"></p-dropdownItem>
826 </ng-container>
827 </cdk-virtual-scroll-viewport>
828 </ng-template>
829 </ng-template>
830 <li *ngIf="filter && (!optionsToDisplay || (optionsToDisplay && optionsToDisplay.length === 0))" class="p-dropdown-empty-message">{{emptyFilterMessage}}</li>
831 </ul>
832 </div>
833 </div>
834 </div>
835 `,
836 animations: [
837 trigger('overlayAnimation', [
838 transition(':enter', [
839 style({ opacity: 0, transform: 'scaleY(0.8)' }),
840 animate('{{showTransitionParams}}')
841 ]),
842 transition(':leave', [
843 animate('{{hideTransitionParams}}', style({ opacity: 0 }))
844 ])
845 ])
846 ],
847 host: {
848 '[class.p-inputwrapper-filled]': 'filled',
849 '[class.p-inputwrapper-focus]': 'focused'
850 },
851 providers: [DROPDOWN_VALUE_ACCESSOR],
852 changeDetection: ChangeDetectionStrategy.OnPush,
853 encapsulation: ViewEncapsulation.None,
854 styles: [".p-dropdown{-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;cursor:pointer;display:-ms-inline-flexbox;display:inline-flex;position:relative;user-select:none}.p-dropdown-clear-icon{margin-top:-.5rem;position:absolute;top:50%}.p-dropdown-trigger{-ms-flex-align:center;-ms-flex-negative:0;-ms-flex-pack:center;align-items:center;display:-ms-flexbox;display:flex;flex-shrink:0;justify-content:center}.p-dropdown-label{-ms-flex:1 1 auto;cursor:pointer;display:block;flex:1 1 auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:1%}.p-dropdown-label-empty{overflow:hidden;visibility:hidden}input.p-dropdown-label{cursor:default}.p-dropdown .p-dropdown-panel{min-width:100%}.p-dropdown-panel{position:absolute}.p-dropdown-items-wrapper{overflow:auto}.p-dropdown-item{cursor:pointer;font-weight:400;overflow:hidden;position:relative;white-space:nowrap}.p-dropdown-items{list-style-type:none;margin:0;padding:0}.p-dropdown-filter{width:100%}.p-dropdown-filter-container{position:relative}.p-dropdown-filter-icon{margin-top:-.5rem;position:absolute;top:50%}.p-fluid .p-dropdown{display:-ms-flexbox;display:flex}.p-fluid .p-dropdown .p-dropdown-label{width:1%}"]
855 },] }
856];
857Dropdown.ctorParameters = () => [
858 { type: ElementRef },
859 { type: Renderer2 },
860 { type: ChangeDetectorRef },
861 { type: NgZone }
862];
863Dropdown.propDecorators = {
864 scrollHeight: [{ type: Input }],
865 filter: [{ type: Input }],
866 name: [{ type: Input }],
867 style: [{ type: Input }],
868 panelStyle: [{ type: Input }],
869 styleClass: [{ type: Input }],
870 panelStyleClass: [{ type: Input }],
871 readonly: [{ type: Input }],
872 required: [{ type: Input }],
873 editable: [{ type: Input }],
874 appendTo: [{ type: Input }],
875 tabindex: [{ type: Input }],
876 placeholder: [{ type: Input }],
877 filterPlaceholder: [{ type: Input }],
878 filterLocale: [{ type: Input }],
879 inputId: [{ type: Input }],
880 selectId: [{ type: Input }],
881 dataKey: [{ type: Input }],
882 filterBy: [{ type: Input }],
883 autofocus: [{ type: Input }],
884 resetFilterOnHide: [{ type: Input }],
885 dropdownIcon: [{ type: Input }],
886 optionLabel: [{ type: Input }],
887 autoDisplayFirst: [{ type: Input }],
888 group: [{ type: Input }],
889 showClear: [{ type: Input }],
890 emptyFilterMessage: [{ type: Input }],
891 virtualScroll: [{ type: Input }],
892 itemSize: [{ type: Input }],
893 autoZIndex: [{ type: Input }],
894 baseZIndex: [{ type: Input }],
895 showTransitionOptions: [{ type: Input }],
896 hideTransitionOptions: [{ type: Input }],
897 ariaFilterLabel: [{ type: Input }],
898 ariaLabelledBy: [{ type: Input }],
899 filterMatchMode: [{ type: Input }],
900 maxlength: [{ type: Input }],
901 tooltip: [{ type: Input }],
902 tooltipPosition: [{ type: Input }],
903 tooltipPositionStyle: [{ type: Input }],
904 tooltipStyleClass: [{ type: Input }],
905 autofocusFilter: [{ type: Input }],
906 onChange: [{ type: Output }],
907 onFocus: [{ type: Output }],
908 onBlur: [{ type: Output }],
909 onClick: [{ type: Output }],
910 onShow: [{ type: Output }],
911 onHide: [{ type: Output }],
912 containerViewChild: [{ type: ViewChild, args: ['container',] }],
913 filterViewChild: [{ type: ViewChild, args: ['filter',] }],
914 accessibleViewChild: [{ type: ViewChild, args: ['in',] }],
915 viewPort: [{ type: ViewChild, args: [CdkVirtualScrollViewport,] }],
916 editableInputViewChild: [{ type: ViewChild, args: ['editableInput',] }],
917 templates: [{ type: ContentChildren, args: [PrimeTemplate,] }],
918 disabled: [{ type: Input }],
919 options: [{ type: Input }]
920};
921class DropdownModule {
922}
923DropdownModule.decorators = [
924 { type: NgModule, args: [{
925 imports: [CommonModule, SharedModule, ScrollingModule, TooltipModule, RippleModule],
926 exports: [Dropdown, SharedModule, ScrollingModule],
927 declarations: [Dropdown, DropdownItem]
928 },] }
929];
930
931/**
932 * Generated bundle index. Do not edit.
933 */
934
935export { DROPDOWN_VALUE_ACCESSOR, Dropdown, DropdownItem, DropdownModule };
936//# sourceMappingURL=primeng-dropdown.js.map