import { NotifyService } from '@farris/ui-notify'; import { OnInit, Input, Output, EventEmitter, ElementRef, ChangeDetectorRef, Renderer2, ViewChild, AfterViewInit, OnDestroy, Inject, Injector, NgZone } from '@angular/core'; import { Subject, interval, of, Observable, Subscription, fromEvent } from 'rxjs'; import { ControlValueAccessor, NgControl } from '@angular/forms'; import { DOCUMENT } from '@angular/common'; import { takeUntil, filter, skip, debounceTime, throttle, take, delayWhen, throwIfEmpty } from 'rxjs/operators'; import { ComboService } from './combo.service'; import { InputGroupComponent } from '@farris/ui-input-group'; import { SelectItem, NormalObject, ComboChanges } from './combo.interface'; import { ComboLocaleService } from './services/combo.locale.service'; import { CommonUtils, reqAnimFrame } from '@farris/ui-common'; import { EventManager } from '@angular/platform-browser'; import ResizeObserver from 'resize-observer-polyfill'; let nextUniqueId = 0; export class BaseComboComponent implements OnInit, AfterViewInit, OnDestroy, ControlValueAccessor { @Input() disabled = false; @Input() readonly = false; @Input() editable = true; @Input() placeholder = ''; @Input() panelWidth = 300; @Input() panelHeight: number | string = 'auto'; @Input() autoWidth = true; @Input() enableClear = true; @Input() mapFields: any; /** 禁用只读时显示 placeholder */ @Input() forcePlaceholder = false; /** 任意输入 20210202 */ @Input() nosearch = false; /** 允许最大输入长度 */ @Input() maxLength; // 鼠标滑过显示文本内容 @Input() enableTitle = true; /** 展示类型: text文本,tag标签。 默认 text */ @Input() viewType: 'text' | 'tag' = 'text'; @Input() set context(value) { this.comboService.context = value; } @Input() set mappingField(v: any) { this.mapFields = v; } get mappingField(): any { return this.mapFields; } @Input() set data(val: NormalObject[]) { this.comboService.data = val; } get data(): NormalObject[] { return this.comboService.data; } @Input() set idField(val: string) { this.comboService.idField = val; } get idField(): string { return this.comboService.idField; } @Input() set valueField(val: string) { this.comboService.valueField = val; } get valueField(): string { return this.comboService.valueField ? this.comboService.valueField : this.idField; } @Input() set textField(val: string) { this.comboService.textField = val; } get textField(): string { return this.comboService.textField; } @Input() set multiSelect(val: boolean) { this.comboService.multiSelect = val; } get multiSelect(): boolean { return this.comboService.multiSelect; } @Input() set uri(val: string) { this.comboService.uri = val; } get uri(): string { return this.comboService.uri; } @Input() set selectedValues(val: string) { this.comboService.selectedValues = val; } get selectedValues(): string { return this.comboService.selectedValues; } get selectedValuesStr() { if (this.selectedValues === null || this.selectedValues === undefined) { this.selectedValues = ''; } return (this.selectedValues) + ''; } @Input() displayText = ''; @Input() maxHeight = 200; @Input() enableCancelSelected = false; /** 远端过滤 */ @Input() get remoteSearch(): boolean { return this.comboService.remoteSearch; } set remoteSearch(val: boolean) { this.comboService.remoteSearch = val; } @Input() beforeShow: (instance?: this) => Observable; @Input() beforeHide: (instance?: this) => Observable; // 如果面板已打开, 点击清空按钮时是否关闭面板。true: 关闭; false: 不关闭; @Input() hidePanelOnClear = false; /** 开启后,ngModel 的值为 valueField or idField; 否则为textField的值 */ @Input() useValue = false; @Input() separator = ','; @Output() showPanel = new EventEmitter(); @Output() hidePanel = new EventEmitter(); @Output() clear = new EventEmitter(); @Output() valueChange = new EventEmitter(); @Output() selectChange = new EventEmitter(); @ViewChild('comboPanel') set cmbPanel(cmp: ElementRef) { if (cmp) { this._cmbPanel = cmp; this.ro.observe(cmp.nativeElement); this._comboPanelCreated$.next(cmp); } else { this._cmbPanel = null; // this.ro.unobserve(this.el.nativeElement); if (this.ro) { this.ro.disconnect(); } this._comboPanelCreated$.next(null); } } @ViewChild('input') input: InputGroupComponent; @ViewChild('input2') input2: ElementRef; public isOpen = false; public comPosition = {}; public destroy$ = new Subject(); public ngControl: NgControl | any = null; public groupIcon = ''; public localeService: ComboLocaleService; public innerPanelHeight: any; public commonUtils: CommonUtils; private _cmbPanel: ElementRef = null; private _comboPanelCreated$ = new Subject(); // private _hasPosited = false; // private _container: Element; private willHide$: Subject = new Subject(); private containerElement: any; /** overlay */ private panelElement: any; private _documentClickEvent: any; set selections(value: NormalObject[]) { this.comboService.selections = value; } get selections(): NormalObject[] { if (this.comboService.selections) { return this.comboService.selections.filter(n => n !== null && n !== undefined); } return []; } private panelListener = null; private ngZone: NgZone = null; private mouseWheelEvent = null; textChangeSubject = new Subject(); private initdataSubscription: Subscription = null; customData = null; private originalText = ''; private isTextChange = false; treeClientSearch = new Subject(); eventMgr: EventManager; private notifySer: NotifyService; private ro: ResizeObserver | null = null; onChange: (value: string | string[]) => void = () => null; onTouched: () => void = () => null; constructor( public el: ElementRef, public cdr: ChangeDetectorRef, @Inject(DOCUMENT) public document: any, public render: Renderer2, public comboService: ComboService, public injector: Injector ) { this.initToggleAction(); this.initSelectionsChangeAction(); this.initDatasChangeAction(); this.commonUtils = this.injector.get(CommonUtils, null); this.willHide$.pipe( takeUntil(this.destroy$) ).subscribe(e => { if (!this.nosearch && this.displayText !== this.originalText) { this.displayText = this.originalText; if (this.isLookup()) { this.onChange(this.displayText); } else { const _displayText = this.comboService.getValue(this.textField); this.onValueChange({ text: _displayText, value: this.selectedValues, selections: this.selections }); } } this.onTouched(); this.hidePanel.emit(this); }); this.ngZone = this.injector.get(NgZone); this.eventMgr = this.injector.get(EventManager); this.emitTextChange(); this.notifySer = this.injector.get(NotifyService, null); } ngOnInit() { this.localeService = this.injector.get(ComboLocaleService, ''); if (this.localeService) { const localConfig = this.localeService.getLocaleConfig(); if (localConfig) { if (!this.placeholder) { this.placeholder = localConfig['placeholder'] || '请选择'; } } } this.comboService.separator = this.separator; } ngAfterViewInit() { const that = this; this.ngControl = this.injector.get(NgControl, null); fromEvent(window, 'resize').pipe( takeUntil(this.destroy$) ).pipe( debounceTime(100), throttle(ev => interval(100)), ).subscribe(() => { this.updatePanelWidth(); if (this.isOpen) { this.comboService.isOpen$.next(false); this.willHide$.next(); } }); if (this.ngZone) { this.ngZone.runOutsideAngular(() => { setTimeout(() => { that.updatePanelWidth(); }); }); let reszieTimer = null; this.ro = new ResizeObserver((e) => { this.ngZone.runOutsideAngular(() => { if (reszieTimer) { clearTimeout(reszieTimer); } reszieTimer = setTimeout(() => { if (that._cmbPanel && that.panelElement) { reqAnimFrame(() => { that.updatePosition(that._cmbPanel.nativeElement); if (that._cmbPanel.nativeElement.className.indexOf('f-area-show') === -1) { that.render.addClass(that._cmbPanel.nativeElement, 'f-area-show'); } }); } }, 10); }); }); } this.comboService.injectService(); } ngOnDestroy(): void { this.destroy$.next(); this.destroy$.complete(); this.comboService.serachValue$.unsubscribe(); if (this.mouseWheelEvent) { this.mouseWheelEvent(); } } private updatePanelWidth() { const { width } = this.getInputSizeInfo(); this.panelWidth = this.autoWidth ? width : this.panelWidth; } onClick($event: any = null) { if ($event) { if ($event.stopPropagation) { $event.stopPropagation(); } else { if ($event.originalEvent) { $event.originalEvent.stopPropagation(); } } } if (this.isOpen) { this.willHide$.next(); } this.comboService.isOpen$.next(!this.isOpen); if (this.input && this.input.textbox) { this.input.textbox.nativeElement.focus(); } } onBlur(event: Event) { this.onTouched(); } onFocus(event: Event) { // // 启用任意输入后,文本框得到焦点后不弹出下拉面板。2021/02/19 // if (this.nosearch) { // return ; // } // if (!this.isOpen) { // this.comboService.isOpen$.next(true); // // 延迟执行变更检测 更新弹出框位置 // of('').pipe(debounceTime(0)).subscribe(() => { // this.cdr.detectChanges(); // }); // } else { // this.hide(); // } } onInputclick($event?: any) { if ($event && $event.stopPropagation) { $event.stopPropagation(); } this.comboService.isOpen$.next(!this.isOpen); } onEnter(event: Event) { } blur() { this.input.textbox.nativeElement.blur(); } focus() { this.input.textbox.nativeElement.focus(); } onClear() { this.selectedValues = ''; this.selections = []; this.onValueChange({ text: '', value: '', selections: [] }); this.clear.emit(); if (this.isOpen && this.hidePanelOnClear) { // this.comboService.isOpen$.next(false); this.willHide$.next(); } } private getInputSizeInfo() { const el: any = this.viewType === 'text' ? this.input.inputGroup : this.input2; return el.nativeElement.getBoundingClientRect(); } private emitTextChange() { return this.textChangeSubject.pipe( debounceTime(200) ).subscribe((r: any) => { const _selectedValues = this.selectedValues; const val = r ? r : this.displayText; if (r === '') { this.onClear(); } if (this.nosearch) { this.onValueChange({ text: r, value: '', selections: this.selections, nosearch: true }); } if (!this.remoteSearch) { if (!this.multiSelect) { if (this.comboService.displayType === 'LOOKUPTREELIST') { this.treeClientSearch.next(val); } else { this.comboService.serachValue$.next(val); } } else { const valArr = (val + '').split(this.separator); const appendVal = valArr[valArr.length - 1] ? valArr[valArr.length - 1] : ''; this.comboService.serachValue$.next(appendVal); } // if (_selectedValues !== this.selectedValues) { // this.onValueChange({ text: this.displayText, value: this.selectedValues, selections: this.selections }); // } } else { this.filterDataOnServer(val, '*'); } }); } private __createPanel(value: any) { let params: any = {}; let method = 'get'; if (value instanceof Object) { const { params: _p, data, method: _m, showDialog } = value; if (showDialog === false) { return; } if (data) { params = {data}; this.customData = data; } else { if (_p) { params = {data: _p}; this.customData = _p; } else { this.customData = null; } } if (_m) { method = _m; } } else if (typeof value === 'boolean') { if (value === false) { return; } } this.initCreatPanelAction(); if (this.uri) { this.updateSelectedValues(); if (this.isLookup()) { this.isOpen = true; } } else { this.isOpen = true; } if (this.comboService.displayType === 'LOOKUPTREELIST') { params.enableFullTree = this['enableFullTree']; params.loadTreeDataType = this['loadTreeDataType']; } if (this.isLookup() && this.input && this.nosearch) { this.input.textbox.nativeElement.disabled = true; } const focusInput = () => { if (this.isLookup() && this.input && this.nosearch) { this.input.textbox.nativeElement.disabled = false; this.input.focus(); } }; this.initdataSubscription = this.comboService.initData(params, method, this.selectedValues).pipe( throwIfEmpty(focusInput) ).subscribe(n => { if (!this.isOpen) { this.isOpen = true; } focusInput(); this.cdr.detectChanges(); }); // 禁止滚动 // this.render.setStyle(this.containerElement, 'pointer-events', 'auto'); this.ngZone.runOutsideAngular(() => { this.registerDocumentEvent(); }); } // 显示前事件 private onBeforeShow() { if (!this.beforeShow) { this.beforeShow = () => of(''); } return this.beforeShow(this).pipe(take(1)); } private isLookup() { return this.comboService.displayType.indexOf('LOOKUP') > -1; } // 隐藏前事件 private onBeforeHide() { if (!this.beforeHide) { this.beforeHide = () => of(''); } this.beforeHide(this) .pipe(take(1)) .subscribe(value => { if (typeof value === 'boolean') { if (value) { this.hide(true); } } else if (typeof value === 'object') { if (value.hide) { this.hide(true); } else { if (value.message) { if (this.notifySer) { this.notifySer.warning(value.message); } else { console.info(value.message); } } } } else { this.hide(true); } }); } // 显示或隐藏下拉框 private initToggleAction() { this.comboService.isOpen$.pipe( debounceTime(20), takeUntil(this.destroy$), skip(1)).subscribe(value => { if (this.readonly || this.disabled) { return; } if (value) { this.onBeforeShow().subscribe((v) => { this.__createPanel(v); }); return; } else { this.onBeforeHide(); } this.cdr.detectChanges(); }); this._comboPanelCreated$.pipe( takeUntil(this.destroy$), filter(value => !!value) ).subscribe((cmp: ElementRef) => { cmp.nativeElement.style.display = ''; this.panelElement.appendChild(cmp.nativeElement); let transitionFlag = true; cmp.nativeElement.addEventListener('transitionend', (e: any) => { if (e.target === e.currentTarget && transitionFlag) { transitionFlag = false; this.showPanel.emit(this); } }); if (this.isLookup()) { cmp.nativeElement.style.width = `${this.panelWidth}px`; cmp.nativeElement.style.height = `${this.panelHeight}px`; this.render.addClass(cmp.nativeElement, 'f-area-show'); } // this.updatePosition(cmp.nativeElement); // this.cdr.detectChanges(); }); this.destroy$.pipe(take(1)).subscribe(() => { this.comboService.closeLoading(); nextUniqueId = 0; if (this.panelListener) { this.panelListener(); } if (this.initdataSubscription) { this.initdataSubscription.unsubscribe(); this.initdataSubscription = null; } this.removePanelElement(); }); } private iframeEventHandle(action: 'addEventListener' | 'removeEventListener') { const iframes = Array.from(document.querySelectorAll('iframe')); if (iframes && iframes.length) { for (const iframe of iframes) { const iframeDoc = iframe.contentDocument; if (iframeDoc) { iframeDoc[action]('mousedown', this._documentClickEvent); iframeDoc[action]('mousewheel', this._documentClickEvent); iframeDoc[action]('DOMMouseScroll', this._documentClickEvent); } } } } private removeDocumentListener() { if (this._documentClickEvent) { document.removeEventListener('mousedown', this._documentClickEvent, true); document.removeEventListener('mousewheel', this._documentClickEvent, true); document.removeEventListener('DOMMouseScroll', this._documentClickEvent, true); this.iframeEventHandle('removeEventListener'); this._documentClickEvent = null; } } private registerDocumentEvent() { // 注册 mousedown 事件 隐藏panel document.addEventListener('mousedown', (this._documentClickEvent = event => { if ( !this.el.nativeElement.contains(event.target) && this._cmbPanel && !this.contains(this._cmbPanel, event) ) { this.comboService.isOpen$.next(false); // this.willHide$.next(); } }), true); document.addEventListener('mousewheel', this._documentClickEvent, true); document.addEventListener('DOMMouseScroll', this._documentClickEvent, true); this.iframeEventHandle('addEventListener'); } // 创建下拉面板时事件 private initCreatPanelAction() { if (this.panelElement) { return; } this.createPanel(document.body); this.panelListener = this.render.listen(this.panelElement, 'click', (e: Event) => { e.stopPropagation(); }); } private removePanelElement() { reqAnimFrame(() => { if (this.panelElement) { document.body.removeChild(this.panelElement); this.panelElement = null; } }); } private initSelectionsChangeAction() { this.comboService.selections$.pipe( takeUntil(this.destroy$), debounceTime(100) ).subscribe(value => { if (value.action === 'initData') { this.onSelectionsChange(this.selections); } else { this.onSelectionsChangeDefault(); } }); } protected initDatasChangeAction() { } // canNull 解决取消选中时依然显示 private onSelectionsChangeDefault() { const _displayText = this.comboService.getValue(this.textField); const _selectedValues = this.comboService.getValue(this.idField); if (this.displayText !== _displayText && !this.nosearch) { this.displayText = _displayText || this.displayText; this.displayText = this.displayText || ''; this.originalText = _selectedValues ? _displayText : this.displayText; } if (this.input) { this.input.textbox.nativeElement.value = this.displayText; } this.selectedValues = (_selectedValues !== '' && _selectedValues !== undefined && _selectedValues !== null) ? _selectedValues : this.selectedValues; if (!this.cdr['destroyed']) { this.cdr.detectChanges(); } } protected onSelectionsChange(v: any[]) { } updateMappingFieldValue(clearMapFields = false) { if ( this.mappingField && this.ngControl && this.ngControl.formDirective && this.ngControl.formDirective.form && this.ngControl.formDirective.form.bindingData ) { const bindingData = this.ngControl.formDirective.form.bindingData; if (clearMapFields) { this.selectedValues = ''; } if (bindingData.setValue) { const bindingPath = this.ngControl.formDirective.form.bindingPath; let pathArr: string[] = []; if (bindingPath) { pathArr = bindingPath.split('/').filter(n => n !== ''); } const mappingField = this.mappingField ? this.mappingField : ''; bindingData.setValue(pathArr.concat(mappingField.split('.')), this.selectedValues, true, true); } else if (this.commonUtils) { this.commonUtils.setValue(bindingData, this.mappingField, this.selectedValues); } } } updateSelectedValues() { if ( this.mappingField && this.ngControl && this.ngControl.formDirective && this.ngControl.formDirective.form && this.ngControl.formDirective.form.bindingData ) { const bindingData = this.ngControl.formDirective.form.bindingData; if (bindingData.getValue) { const bindingPath = this.ngControl.formDirective.form.bindingPath; let pathArr: string[] = []; if (bindingPath) { pathArr = bindingPath.split('/').filter(value => value !== ''); } const mappingField = this.mappingField ? this.mappingField : ''; this.selectedValues = bindingData.getValue(pathArr.concat(mappingField.split('.'))); } else if (this.commonUtils) { this.selectedValues = this.commonUtils.getValue(bindingData, this.mappingField); } } else if (!this.mappingField) { // this.selectedValues = this.displayText } } onTextChange(val?: string) { this.isTextChange = true; if (this.nosearch) { this.selectedValues = val; this.updateMappingFieldValue(this.isLookup()); this.onChange(val); } this.textChangeSubject.next(val); } onValueChange(changes: ComboChanges) { this.displayText = changes.text; this.originalText = this.displayText; if (!this.uri && this.data && this.data.length > 0 && (!this['displayType'] || this.useValue) ) { this.onChange(this.selectedValues); } else { this.onChange(this.displayText); } if (!changes.nosearch) { this.valueChange.emit(changes); } this.updateMappingFieldValue(); this.onTouched(); // if (this.isOpen && changes.emitHidePanel) { this.willHide$.next(); } } onSelect(item: any) { } onUnSelected(item: any) { } /** * emit: 默认为 true; */ hide(emit = true) { if (!this.isOpen) { return; } this.removeDocumentListener(); this.isOpen = false; if (emit) { this.willHide$.next(); } if (this.initdataSubscription) { this.initdataSubscription.unsubscribe(); this.initdataSubscription = null; } this.removePanelElement(); } show() { if (this.isOpen) { return; } this.onBeforeShow().subscribe((value: any) => { this.__createPanel(value); }); this.cdr.detectChanges(); } private createPanel(host: HTMLElement) { this.panelElement = this.document.createElement('div'); this.panelElement.id = `overlay-${nextUniqueId++}`; this.panelElement.classList.add('overlay-pane'); this.panelElement.style.display = 'none'; host.appendChild(this.panelElement); this.comboService.panelElement = this.panelElement; if (this.isLookup()) { const { panelWidth, top, left } = this.getPanelSize(); // const { top, left } = this.getPanelPosition(); // this.render.setStyle(this.panelElement, 'width', `${this.panelWidth}px`); // this.render.setStyle(this.panelElement, 'height', `${this.panelHeight}px`); // this.render.setStyle(this.panelElement, 'top', `${top}px`); // this.render.setStyle(this.panelElement, 'left', `${left}px`); // this.render.setStyle(this.panelElement, 'z-index', `10001`); this.panelElement.style.width = `${this.panelWidth}px`; this.panelElement.style.height = `${this.panelHeight}px`; this.panelElement.style.top = `${top}px`; this.panelElement.style.left = `${left}px`; this.panelElement.style.zIndex = 10001; this.panelElement.classList.add('f-combo-lookup'); } else { this.panelElement.style.overflow = 'hidden'; this.render.setStyle(this.panelElement, 'top', '0'); this.render.setStyle(this.panelElement, 'left', '0'); this.panelElement.classList.add('f-combo-lookup'); } this.panelElement.style.display = ''; } private getPanelSize(target?: Element) { let panelHeight = this.panelHeight; this.innerPanelHeight = 202; if (this.autoWidth) { const { width } = this.getInputSizeInfo(); this.panelWidth = width ? width : this.panelWidth; } // 如果taget高度存在 修改pnaelHeight 用于重定位弹出框位置 if (target && target.tagName && panelHeight === 'auto') { const targetHeight = target.scrollHeight; const isNoRecord = !!target.querySelector('.f-table-norecords-content'); // if (this.uri) { // if (this.data && this.data.length) { // if (this.comboService.displayType === 'LIST' && target.querySelector('.list-group')) { // this.innerPanelHeight = target.querySelector('.list-group')['offsetHeight'] + 2; // } else { // this.innerPanelHeight = targetHeight; // } // } // } else { // this.innerPanelHeight = targetHeight && targetHeight > 10 && !isNoRecord ? Math.floor(targetHeight) : this.panelHeight; // } if (this.data && this.data.length) { if (this.comboService.displayType === 'LIST' && target.querySelector('.list-group')) { this.innerPanelHeight = target.querySelector('.list-group')['offsetHeight'] + 2; } else { this.innerPanelHeight = targetHeight; } } } else if (target && target.tagName && panelHeight && !String(panelHeight).includes('px')) { panelHeight = panelHeight; } let { top, height, left, right } = this.el.nativeElement.getBoundingClientRect(); height = height + 1; const bottom = window.innerHeight - height - top; if (panelHeight === 'auto') { if (this.maxHeight && this.maxHeight > this.innerPanelHeight) { panelHeight = this.innerPanelHeight; } else { panelHeight = this.maxHeight; } } const h = top > bottom ? top : bottom; const below = h === bottom; if (bottom > panelHeight) { top = top + height; } else { if (top > bottom) { if (h < panelHeight) { panelHeight = h - 10; top = 10; } else { top = top - parseInt('' + panelHeight, 10) - 5; } } else { if (h < panelHeight) { panelHeight = h - 10; } top = top + height; } } if (window.innerWidth - left < this.panelWidth) { left = right - 400; } return { panelWidth: this.panelWidth, panelHeight, top, left, below }; } private compatibleScrollTop() { if (document.scrollingElement) { return document.scrollingElement.scrollTop; } return Math.max(window.pageYOffset, document.documentElement.scrollTop, document.body.scrollTop); } private compatibleScrollLeft() { if (document.scrollingElement) { return document.scrollingElement.scrollLeft; } return Math.max(window.pageXOffset, document.documentElement.scrollLeft, document.body.scrollLeft); } // 设置弹出框位置 updatePosition(target: Element) { const { panelHeight, left, top, below } = this.getPanelSize(target); if (!this.isLookup()) { let _top = top; let _height = panelHeight; if (top < 0) { _height = this.innerPanelHeight + top - 10; _top = 10; } _top += this.compatibleScrollTop(); if (this.panelHeight !== 'auto') { if (this.maxHeight < _height) { this.maxHeight = _height as number; } } this.comPosition = { 'left': left + this.compatibleScrollLeft(), 'top': _top, 'width': this.panelWidth, height: _height === 'auto' ? 'auto' : _height, 'max-height': this.maxHeight }; } else { this.comPosition = { 'width': this.panelWidth, 'height': panelHeight }; } this.panelElement.style.overflow = ''; target['style'].display = ''; Object.keys(this.comPosition).forEach(n => { let val = this.comPosition[n]; if (val !== 'auto') { val += 'px'; } this.render.setStyle(target, n, val); }); // target['style'].visibility = 'visible'; return this.comPosition; } contains(el: ElementRef, event: any) { return el.nativeElement.contains(event.target); } protected filterSelections(value: string, data: any[]) { const selectedItems = String(value) .split(this.separator) .map(selectedItem => { const item = data.find(val => selectedItem == this.commonUtils.getValue(this.idField, val) + ''); return item ? this.commonUtils.getValue(this.textField, item) : ''; }); return selectedItems.filter(el => el); } protected updateSelections(selectedValues: string, data: any[]) { if (selectedValues === null || selectedValues === undefined) { this.selections = []; } if (typeof selectedValues === 'boolean' || typeof selectedValues === 'number') { selectedValues = '' + selectedValues; } const selectedItems = selectedValues ? String(selectedValues).split(this.separator).map(val => { if (this.comboService.displayType === 'LOOKUPTREELIST') { return this.comboService.treeNodeToFlatData(data, val, this.idField); } return data.find(_data => '' + val == this.commonUtils.getValue(this.idField, _data) + ''); }) : []; this.selections = selectedItems || []; } private getDisplayText(value, data) { if (value !== null && value !== undefined) { const selectedItems = this.filterSelections(value, data); if (!selectedItems || !selectedItems.length) { return value; } else { return selectedItems.filter(v => !!v).join(this.separator); } } else { return ''; } } writeValue(value: any): void { let data = []; if (this.data instanceof Array) { data = this.data; } else if (this.data) { data = (this.data['items'] as any) instanceof Array ? this.data['items'] : data; } this.originalText = value; this.selectedValues = ''; if (!this.uri && data && data.length > 0) { this.selectedValues = value; this.updateSelections(value, data); this.displayText = this.getDisplayText(value, this.selections || []); this.originalText = this.displayText; } else { // this.displayText = this.getDisplayText(value, this.selections); this.displayText = value; this.updateSelectedValues(); if (!this.selectedValues) { this.selectedValues = value; } if (this.viewType === 'tag' && this.multiSelect && (this.displayText !== null && this.displayText !== undefined)) { const txtArr = this.displayText.split(this.separator).filter(n => n); this.selections = txtArr.reduce((r, c, i) => { r.push({ [this.textField]: c }); return r; }, []); } } this.cdr.markForCheck(); } registerOnChange(fn: any): void { this.onChange = fn; } registerOnTouched(fn: any): void { this.onTouched = fn; } setDisabledState?(isDisabled: boolean): void { this.disabled = isDisabled; this.cdr.markForCheck(); } filterDataOnServer(searchValue, searchField) { } }