import { Component, EventEmitter, Input, Output, forwardRef, OnChanges, SimpleChanges, OnInit, ElementRef, ViewChild, AfterViewInit, HostListener, Renderer } from '@angular/core'; import { IDropDownOption, DropDownOptionType, DropDownTypes } from "./dropdown-models"; import { ValidatableComponent } from './../validation/validatable.component'; import template from './dropdown.component.html'; @Component({ selector: 'sdc-dropdown', template: template }) export class DropDownComponent extends ValidatableComponent implements OnChanges, OnInit { @Output('changed') changeEmitter:EventEmitter = new EventEmitter(); @Input() label: string; @Input() options: IDropDownOption[]; @Input() disabled: boolean; @Input() placeHolder: string; @Input() required: boolean; @Input() maxHeight: number; @Input() selectedOption: IDropDownOption; @Input() type: DropDownTypes = DropDownTypes.Regular; @ViewChild('dropDownWrapper') dropDownWrapper: ElementRef; @ViewChild('optionsContainerElement') optionsContainerElement: ElementRef; @HostListener('document:click', ['$event']) onClick(e) { this.onClickDocument(e); } private bottomVisible = true; private myRenderer: Renderer; // Drop-down show/hide flag. default is false (closed) public show = false; // Export DropDownOptionType enum so we can use it on the template public cIDropDownOptionType = DropDownOptionType; public cIDropDownTypes = DropDownTypes; // Configure unselectable option types private unselectableOptions = [ DropDownOptionType.Disable, DropDownOptionType.Header, DropDownOptionType.HorizontalLine ]; // Set or unset Group style on drop-down public isGroupDesign = false; public animation_init = false; public allOptions: IDropDownOption[]; public filterValue: string; constructor(public renderer: Renderer) { super(); this.myRenderer = renderer; this.maxHeight = 244; this.filterValue = ''; } ngOnInit(): void { if (this.options) { this.allOptions = this.options; if (this.options.find(option => option.type === DropDownOptionType.Header)) { this.isGroupDesign = true; } } } ngOnChanges(changes: SimpleChanges): void { console.log("ngOnChanges"); if (changes.selectedOption && changes.selectedOption.currentValue !== changes.selectedOption.previousValue) { if (typeof changes.selectedOption.currentValue === 'string' && this.isSelectable(changes.selectedOption.currentValue)) { this.setSelected(changes.selectedOption.currentValue); } else if (this.isSelectable(changes.selectedOption.currentValue.value)) { this.setSelected(changes.selectedOption.currentValue.value); } else { this.setSelected(undefined); } } } public getValue(): any { return this.selectedOption && this.selectedOption.value; } public selectOption = (option: IDropDownOption | string, event?): void => { if (event) { event.stopPropagation(); } if (this.type === DropDownTypes.Headless) { // Hide the options when in headless mode and user select option. this.myRenderer.setElementStyle(this.dropDownWrapper.nativeElement, 'display', 'none'); } if (typeof option === 'string' && this.isSelectable(option)) { this.setSelected(option); } else if (this.isSelectable((option as IDropDownOption).value)) { this.setSelected((option as IDropDownOption).value); } } public toggleDropdown = (event?): void => { if (event) { event.stopPropagation(); } if (this.type === DropDownTypes.Headless) { // Show the options when in headless mode. this.myRenderer.setElementStyle(this.dropDownWrapper.nativeElement, 'display', 'block'); } if (this.disabled) { return; } this.animation_init = true; this.bottomVisible = this.isBottomVisible(); this.show = !this.show; } public filterOptions = (filterValue): void => { if (filterValue.length >= 1 && !this.show) { this.toggleDropdown(); } if (this.selectedOption) { this.selectedOption = null; } this.options = this.allOptions.filter((option) => { return option.value.toLowerCase().indexOf(filterValue.toLowerCase()) > -1; }); } private isSelectable = (value: string): boolean => { const option: IDropDownOption = this.options.find(o => o.value === value); if (!option) { return false; } if (!option.type) { return true; } return !this.unselectableOptions.find(optionType => optionType === option.type); } private setSelected = (value: string): void => { this.selectedOption = this.options.find(o => o.value === value); if (this.type === DropDownTypes.Auto) { this.filterValue = value; } this.show = false; this.changeEmitter.next(this.selectedOption); } private isBottomVisible = (): boolean => { const windowPos = window.innerHeight + window.pageYOffset; const boundingRect = this.dropDownWrapper.nativeElement.getBoundingClientRect(); const dropDownPos = boundingRect.top + boundingRect.height + this.maxHeight; return windowPos > dropDownPos; } private onClickDocument = (event): void => { if (this.type === DropDownTypes.Headless) { if (!this.optionsContainerElement.nativeElement.contains(event.target)) { this.show = false; } } else { if (!this.dropDownWrapper.nativeElement.contains(event.target)) { this.show = false; } } } }