import { Component, OnInit, OnDestroy, Input, Output, ElementRef, EventEmitter, Renderer2, forwardRef, ChangeDetectorRef, ViewEncapsulation, ViewChild, HostListener} from '@angular/core'; import { InputModule } from "./../../base/input/input.module"; import * as pinyinUtil from'../../scripts/pinyinjs/pinyinUtil'; import { DOWN_ARROW, ENTER, TAB } from '@angular/cdk/keycodes'; import { CdkConnectedOverlay, ConnectedOverlayPositionChange } from '@angular/cdk/overlay'; import { measureScrollbar } from '../../utils/mesureScrollBar'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; @Component({ encapsulation: ViewEncapsulation.None, selector: 'cm-sortselector', templateUrl: './sortselector.component.html', styleUrls: ['./sortselector.component.less'], providers : [ { provide : NG_VALUE_ACCESSOR, useExisting: forwardRef(() => SortselectorComponent), multi : true } ], }) export class SortselectorComponent implements OnInit, ControlValueAccessor, OnDestroy { _cmSortOptions:any[]; selectedOptionModel:any[] = []; optionsList:any[] = []; value:any[] = []; _isOpen:boolean = false; _cmPlaceHolder:string = "placeholder"; _selectedOptions:any[] = [];//已选中选项 _searchText:string = ''; cmShowSearch:boolean = false; cmMultiple:boolean = true; _triggerWidth:any; _el: HTMLElement; _mode:string; _filterOptions:any[] = []; _dropDownPosition: 'top' | 'center' | 'bottom' = 'bottom'; _offsetX:number = 0; _cmTooltip:boolean = false; _size:string; _class:any; optionIsNull:boolean = false; constructor(private _elementRef: ElementRef, private _renderer: Renderer2, private _cdr: ChangeDetectorRef) { this._el = this._elementRef.nativeElement; } // ngModel Access onChange: (value: any) => void = () => null; onTouched: () => void = () => null; @ViewChild(CdkConnectedOverlay) _cdkOverlay: CdkConnectedOverlay; @ViewChild('trigger') trigger: ElementRef; @ViewChild('searchInput') searchInputElementRef:any; @Input () set cmSortOptions(cmSortOptions:any[]){ if(cmSortOptions && cmSortOptions.length > 0){ this._cmSortOptions = JSON.parse(JSON.stringify(cmSortOptions)); this._cmSortOptions = this.setSortArray(cmSortOptions); this.handlerData(this._cmSortOptions); this._cmSortOptions = JSON.parse(JSON.stringify(this._filterOptions)); if(this.selectedOptionModel.length > 0){ let historySelectedList = this.selectedOptionModel.toString(); this.initOptions(); if (this.selectedOptionModel.toString() !== historySelectedList) { this.cmClosePanel.emit(this.selectedOptionModel); this.onChange(this.selectedOptionModel); }; } }else{ this._cmSortOptions = []; if(this.selectedOptionModel.length > 0){ this.selectedOptionModel = []; this._selectedOptions = []; this.cmClosePanel.emit(this.selectedOptionModel); this.onChange(this.selectedOptionModel); } } } @Input () set cmPlaceHolder(cmPlaceHolder:string){ if(cmPlaceHolder.length > 0){ this._cmPlaceHolder = cmPlaceHolder; }else{ this._cmPlaceHolder = "请选择"; } } @Input() set cmMode(value: string) { this._mode = value; if (this._mode === 'multiple') { this.cmMultiple = true; } else if(this._mode === 'single'){ this.cmMultiple = false; } } @Input () set cmTooltip(cmTooltip:boolean){ this._cmTooltip = cmTooltip ? true : false; } @Input() set cmSize(value: string) { this._size = { large: 'lg', small: 'sm' }[ value ] || 'sm'; this._class ={[`cm-sortselector-${this._size}`]: true} ; } get _arrowCls(): any { return { [`cm-sortselector-arrow`] : true, [`cm-sortselector-arrow-expand`]: this._isOpen }; } @Output() cmClosePanel = new EventEmitter(); //取首字母 setSortArray(cmSortOptions:any[]){ if(cmSortOptions && cmSortOptions.length > 0){ let dataArr = 'abcdefghijklmnopqrstuvwxyz0123456789'; let optLength = cmSortOptions.length; for(let i = 0; i < optLength; i++){ let opt = cmSortOptions[i]; let firstLetter = opt['label'].substr(0,1).toUpperCase(); if(dataArr.indexOf(firstLetter) >= 0){ opt['code'] = firstLetter; }else{ opt['code'] = (pinyinUtil.pinyinUtil.getFirstLetter(firstLetter)).toUpperCase(); } } return cmSortOptions; } } //处理数据 handlerData(cmSortOptions:any[]){ this._filterOptions = []; let optLength = cmSortOptions.length; for(let i = 0; i < optLength; i++){ let opt = cmSortOptions[i]; this._filterOptions = this.changeOptionByCode(opt, this._filterOptions); } } //分组 changeOptionByCode(obj:Object, data:any[]){ if(data){ obj['isSelected'] = false; let hasCode:boolean = false; let len = data.length; for(let i = 0; i < len; i++){ if(obj['code'] && data[i]['code'] == obj['code']){ hasCode = true; data[i]['list'].push(obj) break } } //不存在 if(!hasCode && obj['code']){ data[len] = { code: obj['code'], list: [obj] } } return data; } } clcikOptionHandler(e:any, option:any){ this._searchText = ''; console.log(option) if(this.cmMultiple){ if(this.selectedOptionModel.indexOf(option.value) < 0){ this._selectedOptions.push(option); this.selectedOptionModel.push(option.value); this.updateFilterOption(option, this._cmSortOptions); this._filterOptions = JSON.parse(JSON.stringify(this._cmSortOptions)); this.cmClosePanel.emit(this.selectedOptionModel); this.onChange(this.selectedOptionModel); }else{ this.updateFilterOption(option, this._cmSortOptions); this.unSelectMultipleOption(option,null); } setTimeout(() => { this._cdkOverlay.overlayRef.updatePosition(); }, 0); }else{ this.selectedOptionModel = []; this._selectedOptions = []; this.selectedOptionModel[0] = option.value this._selectedOptions[0] = option; this.updateFilterOption(option, this._cmSortOptions); this._filterOptions = JSON.parse(JSON.stringify(this._cmSortOptions)); this.closeDropDown(); // if(option.isSelected && this.selectedOptionModel.length > 0){ // this.selectedOptionModel = []; // this._selectedOptions = []; // this.updateFilterOption(option, this._cmSortOptions); // this._filterOptions = JSON.parse(JSON.stringify(this._cmSortOptions)); // }else if(this.selectedOptionModel.length <= 0){ // this.selectedOptionModel.push(option.value) // this._selectedOptions.push(option); // this.updateFilterOption(option, this._cmSortOptions); // this._filterOptions = JSON.parse(JSON.stringify(this._cmSortOptions)); // } } e.stopPropagation() } closeDropDown(){ if (!this._isOpen) { return; } this._isOpen = !this._isOpen; this._searchText = ''; if(this._selectedOptions.length <= 0)this.cmShowSearch = false; this.cmClosePanel.emit(this.selectedOptionModel); this.onChange(this.selectedOptionModel); } @HostListener('click', [ '$event' ]) onClick(e: MouseEvent): void { e.stopPropagation(); this._isOpen = !this._isOpen; this.cmShowSearch = true; /** wait for search display */ setTimeout(()=> { this.searchInputElementRef.nativeElement.focus(); }); } clearSearchText(): void { this._searchText = ''; setTimeout(() => { if(this._cmSortOptions.length > 0){ this.updateFilterOption(null, null); } }, 500); } updateWidth(element: HTMLInputElement, text: string): void { if (text) { /** wait for scroll width change */ setTimeout(() => { this._renderer.setStyle(element, 'width', `${element.scrollWidth}px`); }); } else { this._renderer.removeStyle(element, 'width'); } } //删除某个选中的选项 unSelectMultipleOption(option:any,$event:any){ let len = this._selectedOptions.length; for(let i =0; i < len; i++){ let item = this._selectedOptions[i]; if(item.value == option.value){ this._selectedOptions.splice(i,1); this.selectedOptionModel.splice(i,1); if(this._selectedOptions.length <= 0 ){ this.cmShowSearch = false; } break; } } this.updateFilterOption(option, this._cmSortOptions); this.updateFilterOption(option, this._filterOptions); this.cmClosePanel.emit(this.selectedOptionModel); this.onChange(this.selectedOptionModel); $event ? $event.stopPropagation() : null; } //更新下拉框数据 updateFilterOption(option:any, data:any[]) { if(option && data){ data.forEach((obj) => { let len = obj.list.length; for(let i = 0; i < len; i++){ let listItem = obj.list[i]; if(option.value == listItem.value){ // obj.list.splice(i,1); obj.list[i]['isSelected'] = !obj.list[i]['isSelected']; if(this.cmMultiple) return; }else{ if(!this.cmMultiple){ obj.list[i]['isSelected'] = false; } } } }); }else if(this._searchText){//搜索 let searchtext = this._searchText; let newOptions = []; newOptions = JSON.parse(JSON.stringify(this._cmSortOptions)); let len = newOptions.length; for(let i = 0; i < len; i++){ newOptions[i]['list'] = []; let listLength = this._cmSortOptions[i]['list'].length; for(let j = 0; j < listLength; j++){ let listItem =this._cmSortOptions[i]['list'][j]; if(listItem['label'].indexOf(searchtext) >= 0){ newOptions[i]['list'].push(listItem); } } } this._filterOptions = newOptions; this.checkOptionsIsNull(this._filterOptions); }else{ this._filterOptions = JSON.parse(JSON.stringify(this._cmSortOptions)); this.optionIsNull = false; } } checkOptionsIsNull(options:any){ let isNull = true; if(options.length > 0){ let len = options.length; for(let i = 0; i < len; i++){ if( options[i]['list'] && options[i]['list'].length > 0){ isNull = false; } } this.optionIsNull = isNull; } } _getTriggerRect(): ClientRect { return this.trigger.nativeElement.getBoundingClientRect(); } onPositionChange(position: ConnectedOverlayPositionChange): void { this.reposition(); this._dropDownPosition = position.connectionPair.originY; } reposition(): void { if (typeof window !== 'undefined' && this._isOpen && this._cdkOverlay && this._cdkOverlay.overlayRef) { const originElement = this._cdkOverlay.origin.elementRef.nativeElement; const overlayElement = this._cdkOverlay.overlayRef.overlayElement as HTMLElement; const originX = originElement.getBoundingClientRect().x; const overlayWidth = overlayElement.getBoundingClientRect().width < this._getTriggerRect().width ? this._getTriggerRect().width : overlayElement.getBoundingClientRect().width; overlayElement.style.width = overlayWidth + 'px'; const margin = window.innerWidth - originX - overlayWidth; this._offsetX = margin > 0 ? 0 : margin - (measureScrollbar() || 15); this._cdr.detectChanges(); } } private _updateValue(value: any[] | any): void { if (this.selectedOptionModel === value) { return; } if ((value == null) || value.length === 0) { this.selectedOptionModel = []; } else { this.selectedOptionModel = value; this.cmShowSearch = true; } this.initOptions(); } private initOptions(){ let selectArr = JSON.parse(JSON.stringify(this.selectedOptionModel)); this._filterOptions = JSON.parse(JSON.stringify(this._cmSortOptions)); this._selectedOptions = []; this.selectedOptionModel = []; this.setOptionsUnselected();//全部未选中 for(let i = 0; i < this._filterOptions.length; i++){ let listItems = this._filterOptions[i]['list']; for(let value of selectArr){ for(let j = 0; j < listItems.length; j++){ if(value == listItems[j]['value']){ this.updateFilterOption(listItems[j], this._cmSortOptions); this.updateFilterOption(listItems[j], this._filterOptions); this._selectedOptions.push(listItems[j]); this.selectedOptionModel.push(value); break; } } } } } setOptionsUnselected(){ for(let i = 0; i < this._filterOptions.length; i++){ let listItems = this._filterOptions[i]['list']; for(let value of this.selectedOptionModel){ for(let j = 0; j < listItems.length; j++){ listItems[j]['isSelected'] = false; } } } } writeValue(value: any | any[]): void { this.onChange(value); this._updateValue(value); } registerOnChange(fn: (value: any | any[]) => void): void { this.onChange = fn; } registerOnTouched(fn: () => void): void { this.onTouched = fn; } onAttach(): void { this.reposition(); } ngOnInit() { } ngOnDestroy() { } }