UNPKG

ng-devui

Version:

DevUI components based on Angular

1 lines 89.8 kB
{"version":3,"file":"ng-devui-cascader.mjs","sources":["../../devui/cascader/cascader.service.ts","../../devui/cascader/cascader-li.component.ts","../../devui/cascader/cascader-li.component.html","../../devui/cascader/cascader.component.ts","../../devui/cascader/cascader.component.html","../../devui/cascader/cascader.module.ts","../../devui/cascader/ng-devui-cascader.ts"],"sourcesContent":["import { Injectable, OnDestroy } from '@angular/core';\r\nimport { cloneDeep } from 'lodash-es';\r\nimport { Observable, Subject } from 'rxjs';\r\nimport { CascaderItem } from './cascader.type';\r\n\r\n@Injectable()\r\nexport class CascaderService implements OnDestroy {\r\n _currentValue: Array<string | number> = [];\r\n\r\n multipleValue: Array<string | number>[] = [];\r\n\r\n options: CascaderItem[];\r\n\r\n columnList: CascaderItem[][] = [];\r\n searchResultList = [];\r\n\r\n canSelectParent = false;\r\n\r\n isMultiple = false;\r\n\r\n isLazyLoad = false;\r\n lazyloadCache = {};\r\n checkboxRelation = { upward: true, downward: true };\r\n\r\n loadChildrenFn: (value: CascaderItem) => Promise<CascaderItem[]> | Observable<CascaderItem[]>;\r\n\r\n set currentValue(value: Array<string | number>) {\r\n this._currentValue = value.filter((item) => item !== undefined);\r\n this.currentValueChange.next(this._currentValue);\r\n }\r\n\r\n get currentValue() {\r\n return this._currentValue;\r\n }\r\n\r\n set currentMultipleValue(value) {\r\n this.resetNodeStatus();\r\n this.multipleValue = value;\r\n }\r\n\r\n get currentMultipleValue() {\r\n this.multipleValue = [];\r\n this.getMultipleValue([], this.options);\r\n return this.multipleValue;\r\n }\r\n\r\n readonly closeMianDropdown = new Subject<void>();\r\n readonly currentValueChange = new Subject<Array<string | number>>();\r\n readonly resetStatus = new Subject<void>();\r\n readonly openDrawer = new Subject<void>();\r\n readonly updateShowText = new Subject<void>();\r\n readonly updateTagList = new Subject<{\r\n isAdd: boolean;\r\n option: CascaderItem;\r\n isEmit: boolean; // 是否触发onchanges,对外发出值\r\n }>();\r\n\r\n initOptions(options: CascaderItem[]): void {\r\n this.columnList = [];\r\n this.options = cloneDeep(options);\r\n // 标记根节点\r\n this.options.forEach((t) => {\r\n t.isRoot = true;\r\n });\r\n this.columnList.push(this.options);\r\n }\r\n\r\n openColumn(option: CascaderItem, colIndex: number, islazyLoad: boolean, reload = false): void {\r\n this.clearTargetActive(this.columnList[colIndex].find((t) => t.active));\r\n option.active = true;\r\n this.columnList.splice(colIndex + 1);\r\n\r\n if (option.children && option.children.length) {\r\n this.columnList.push(option.children);\r\n this.openDrawer.next();\r\n } else if (islazyLoad) {\r\n option._loading = true;\r\n\r\n const fn = this.loadChildrenFn(option);\r\n\r\n if ((fn as Promise<CascaderItem[]>).then) {\r\n (fn as Promise<CascaderItem[]>).then((res) => {\r\n this.columnList.splice(colIndex + 1); // 防止多个同时懒加载,造成多余的添加\r\n option.children = res || [];\r\n option._loading = false;\r\n this.columnList.push(res || []);\r\n this.openDrawer.next();\r\n\r\n if (this.isMultiple) {\r\n this.updateOptionCheckedStatus(option.value, option.checked, true, true, !reload);\r\n }\r\n if (reload) {\r\n if (!this.isMultiple) {\r\n this.updateOptionByValue();\r\n }\r\n this.updateShowText.next();\r\n }\r\n });\r\n } else {\r\n (fn as Observable<CascaderItem[]>).subscribe((res) => {\r\n this.columnList.splice(colIndex + 1); // 防止多个同时懒加载,造成多余的添加\r\n option.children = res || [];\r\n option._loading = false;\r\n this.columnList.push(res || []);\r\n this.openDrawer.next();\r\n\r\n if (this.isMultiple) {\r\n this.updateOptionCheckedStatus(option.value, option.checked, true, true, !reload);\r\n }\r\n\r\n if (reload) {\r\n if (!this.isMultiple) {\r\n this.updateOptionByValue();\r\n }\r\n this.updateShowText.next();\r\n }\r\n });\r\n }\r\n }\r\n }\r\n\r\n clearTargetActive(option: CascaderItem): void {\r\n if (!option) {\r\n return;\r\n }\r\n option.active = false;\r\n if (option.children) {\r\n this.clearTargetActive(option.children.find((t) => t.active));\r\n }\r\n }\r\n\r\n setCurrentValue(): void {\r\n this.currentValue = this.columnList.map((listItem) => listItem.find((optionItem) => optionItem.active)?.value);\r\n }\r\n\r\n updateOptionByValue(): void {\r\n this.resetNodeStatus();\r\n this.columnList = [this.options];\r\n for (let index = 0; index < this.currentValue.length; index++) {\r\n const target = this.columnList[index]?.find((listItem) => listItem.value === this.currentValue[index]);\r\n\r\n if (target) {\r\n target.active = true;\r\n if (target.children && target.children.length) {\r\n // 有子菜单展开子菜单\r\n this.columnList.push(target.children);\r\n } else if (this.isLazyLoad) {\r\n // 懒加载没有子菜单的情况下,非叶子节点执行展开,叶子节点执行选中\r\n this.openColumn(target, index, !target.isLeaf, !target.isLeaf);\r\n break;\r\n }\r\n } else {\r\n break;\r\n }\r\n }\r\n }\r\n\r\n lazyloadMultipleChild(target: CascaderItem, index: number) {\r\n if (!this.lazyloadCache[target.value]) {\r\n this.lazyloadCache[target.value] = true;\r\n this.openColumn(target, index, true, true);\r\n }\r\n }\r\n\r\n resetNodeStatus(option: CascaderItem[] = this.options): void {\r\n option.forEach((item) => {\r\n item.active = false;\r\n item.checked = false;\r\n item.halfChecked = false;\r\n if (item.children) {\r\n this.resetNodeStatus(item.children);\r\n }\r\n });\r\n }\r\n\r\n // 在多选模式下,更新节点树的checked状态\r\n updateOptionCheckedStatus(targetValue: string | number, checked: boolean, upward = true, downward = true, isEmit = true): void {\r\n let targetNode = this.options.find((t) => t.value === targetValue);\r\n // 当主下拉列表包含了目标,即目标无父节点\r\n if (targetNode) {\r\n targetNode.checked = checked;\r\n targetNode.halfChecked = false;\r\n if (targetNode.children && downward) {\r\n this.updateChildrenChecked(targetNode, checked, isEmit);\r\n }\r\n } else {\r\n // 当存在父节点时,需要检查同级节点来确定父节点状态\r\n const parentNode = this.getParentNode(targetValue);\r\n targetNode = parentNode.children.find((t) => t.value === targetValue);\r\n\r\n targetNode.checked = checked;\r\n targetNode.halfChecked = false;\r\n if (upward) {\r\n this.updateParentChecked(parentNode, isEmit);\r\n }\r\n if (targetNode.children && downward) {\r\n this.updateChildrenChecked(targetNode, checked, isEmit);\r\n }\r\n }\r\n }\r\n\r\n // 子节点按父节点状态更新\r\n updateChildrenChecked(node: CascaderItem, checked: boolean, isEmit: boolean) {\r\n let hasDisable = false;\r\n node.children.forEach((child) => {\r\n if (!child.disabled) {\r\n child.checked = checked;\r\n child.halfChecked = false;\r\n if (child.children && child.children.length) {\r\n if (this.canSelectParent) {\r\n this.updateTagList.next({\r\n isAdd: checked,\r\n option: child,\r\n isEmit,\r\n });\r\n }\r\n this.updateChildrenChecked(child, checked, isEmit);\r\n } else {\r\n this.updateTagList.next({\r\n isAdd: checked,\r\n option: child,\r\n isEmit,\r\n });\r\n }\r\n } else {\r\n hasDisable = true;\r\n }\r\n });\r\n\r\n if (hasDisable && !this.canSelectParent) {\r\n this.updateParentChecked(node, isEmit);\r\n }\r\n }\r\n\r\n // 父节点按所有子节点状态更新\r\n updateParentChecked(node: CascaderItem, isEmit: boolean) {\r\n const checkedChild = node.children.find((t) => t.checked);\r\n const halfcheckedChild = node.children.find((t) => t.halfChecked);\r\n const uncheckedChild = node.children.find((t) => !t.halfChecked && !t.checked);\r\n\r\n if (halfcheckedChild || (checkedChild && uncheckedChild)) {\r\n node.checked = false;\r\n node.halfChecked = true;\r\n } else if (!checkedChild && !halfcheckedChild) {\r\n node.checked = false;\r\n node.halfChecked = false;\r\n } else {\r\n node.checked = true;\r\n node.halfChecked = false;\r\n }\r\n\r\n if (this.canSelectParent) {\r\n this.updateTagList.next({\r\n isAdd: node.checked,\r\n option: node,\r\n isEmit,\r\n });\r\n }\r\n\r\n // 如果此节点非根节点,则继续找它的父节点进行更新\r\n if (!node.isRoot) {\r\n this.updateParentChecked(this.getParentNode(node.value), isEmit);\r\n }\r\n }\r\n\r\n // 获取父节点\r\n getParentNode(childValue: string | number): CascaderItem {\r\n const queue = [...this.options];\r\n let cur: CascaderItem;\r\n while (queue.length) {\r\n cur = queue.shift();\r\n if (cur.children && cur.children.find((t) => t.value === childValue)) {\r\n break;\r\n } else if (cur.children) {\r\n queue.push(...cur.children);\r\n }\r\n }\r\n return cur;\r\n }\r\n\r\n getMultipleValue(value, option: CascaderItem[]): void {\r\n const isNoRelation = !this.checkboxRelation.downward || !this.checkboxRelation.upward;\r\n option.forEach((item) => {\r\n const _value = [...value];\r\n _value.push(item.value);\r\n if (item.children && item.children.length && (item.checked || item.halfChecked)) {\r\n this.getMultipleValue(_value, item.children);\r\n if (isNoRelation) {\r\n this.multipleValue.push(_value);\r\n }\r\n } else if (item.checked) {\r\n this.multipleValue.push(_value);\r\n } else if (isNoRelation && item.children?.length) {\r\n this.getMultipleValue(_value, item.children);\r\n }\r\n });\r\n }\r\n\r\n closeAllDropdown(): void {\r\n this.closeMianDropdown.next();\r\n }\r\n\r\n // 搜索功能\r\n searchByString(str: string, currentlabel?: string, currentValue: Array<string | number> = [], list = this.options): void {\r\n list.forEach((item) => {\r\n const label = currentlabel ? currentlabel + ' / ' + item.label : item.label;\r\n const valueList = [...currentValue, item.value];\r\n if (item.children && item.children.length) {\r\n this.searchByString(str, label, valueList, item.children);\r\n } else {\r\n if (!item.disabled && label.toLowerCase().indexOf(str.toLowerCase()) !== -1) {\r\n this.searchResultList.push({\r\n label,\r\n valueList,\r\n checked: item.checked,\r\n });\r\n }\r\n }\r\n });\r\n }\r\n\r\n ngOnDestroy(): void {\r\n this.closeMianDropdown.complete();\r\n this.currentValueChange.complete();\r\n this.updateTagList.complete();\r\n this.resetStatus.complete();\r\n this.openDrawer.complete();\r\n }\r\n}\r\n","import { ChangeDetectorRef, Component, HostListener, Input, OnDestroy, OnInit, TemplateRef } from '@angular/core';\nimport { Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { CascaderService } from './cascader.service';\nimport { CascaderItem } from './cascader.type';\n\n@Component({\n selector: 'd-cascader-li',\n templateUrl: './cascader-li.component.html',\n styleUrls: ['./cascader-li.component.scss'],\n})\nexport class CascaderLiComponent implements OnInit, OnDestroy {\n @Input() width = 200;\n @Input() trigger: 'click' | 'hover' = 'hover';\n @Input() option: CascaderItem;\n @Input() multiple = false;\n @Input() canSelectParent = false;\n @Input() colIndex: number;\n @Input() dropDownItemTemplate: TemplateRef<any>;\n @Input() isLazyLoad: boolean;\n @Input() checkboxRelation = { upward: true, downward: true };\n\n dropdownEl: Element;\n isLeaf: boolean;\n selected: boolean;\n halfCheck: boolean;\n active: boolean;\n\n unsubscribe$ = new Subject<void>();\n\n @HostListener('click', ['$event'])\n onClick(event: Event) {\n event.stopPropagation();\n }\n\n @HostListener('mouseenter', ['$event'])\n onMouseEnter(event) {\n if (this.trigger === 'hover') {\n if (this.option.disabled) {\n return;\n }\n this.cascaderSrv.openColumn(this.option, this.colIndex, false);\n }\n }\n\n constructor(\n private cascaderSrv: CascaderService,\n private cdr: ChangeDetectorRef\n ) { }\n\n ngOnInit() {\n if (this.isLazyLoad) {\n this.isLeaf = !!this.option.isLeaf;\n } else { // 当不是懒加载时可以通过children是否为空来判断是否为叶子节点\n this.isLeaf = this.option.isLeaf || !(this.option.children && this.option.children.length);\n }\n\n this.initObserable();\n }\n\n initObserable(): void {\n this.cascaderSrv.resetStatus.pipe(\n takeUntil(this.unsubscribe$)\n ).subscribe(res => {\n this.selected = false;\n this.halfCheck = false;\n this.active = false;\n });\n }\n\n clickLeaf(): void {\n if (!this.option.disabled && !this.multiple) {\n this.cascaderSrv.openColumn(this.option, this.colIndex, false);\n this.option.active = true;\n this.cascaderSrv.setCurrentValue();\n this.cascaderSrv.closeAllDropdown();\n }\n }\n\n clickItem(): void {\n if (this.option.disabled) {\n return;\n }\n this.cascaderSrv.openColumn(this.option, this.colIndex, this.isLazyLoad);\n if (this.canSelectParent && !this.multiple) {\n this.cascaderSrv.setCurrentValue();\n }\n }\n\n clickCheckbox(event: Event): void {\n if (this.option.disabled) {\n return;\n }\n event.stopPropagation();\n // 如果是半选状态,更新为false,其他状态则更新为与checked相反\n const status = !!this.option.halfChecked;\n this.cascaderSrv.updateOptionCheckedStatus(\n this.option.value,\n this.option.halfChecked ? false : !this.option.checked,\n this.checkboxRelation.upward,\n this.checkboxRelation.downward,\n );\n\n if (status) {\n this.option.halfChecked = false;\n }\n\n if (this.isLeaf || this.canSelectParent) {\n this.updateValue(this.option.checked);\n }\n }\n\n // 阻止checkbox本身的点击事件变化\n avoidCheckboxChange(): boolean {\n return false;\n }\n\n updateValue(checked: boolean): void {\n this.cascaderSrv.updateTagList.next({\n isAdd: checked,\n option: this.option,\n isEmit: true\n });\n }\n\n ngOnDestroy(): void {\n this.unsubscribe$.next();\n this.unsubscribe$.complete();\n }\n\n}\n","<li *ngIf=\"!isLeaf\" role=\"menuitem\" [ngClass]=\"{ disabled: option.disabled, 'devui-leaf-active': option.active }\" (click)=\"clickItem()\">\n <div class=\"devui-dropdown-item\">\n <d-checkbox\n *ngIf=\"multiple\"\n class=\"devui-dropdown-item-checkbox\"\n [disabled]=\"option.disabled\"\n [isShowTitle]=\"false\"\n [halfchecked]=\"option.halfChecked\"\n (click)=\"clickCheckbox($event)\"\n [ngModel]=\"option.checked\"\n [beforeChange]=\"avoidCheckboxChange\"\n ></d-checkbox>\n <i *ngIf=\"option.icon\" class=\"icon {{ option.icon }}\"></i>\n <span class=\"dropdown-item-label\">\n <ng-template\n [ngTemplateOutlet]=\"dropDownItemTemplate || defaultDropdownItemTemplate\"\n [ngTemplateOutletContext]=\"{\n label: option.label,\n option: option\n }\"\n >\n </ng-template>\n </span>\n <svg\n *ngIf=\"!option._loading\"\n style=\"float: right\"\n width=\"16px\"\n height=\"16px\"\n viewBox=\"0 0 16 16\"\n class=\"icon devui-cascader-icon-right\"\n >\n <g id=\"icon-icon-chevron-right-2\" stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\">\n <g\n id=\"ipd_right\"\n transform=\"translate(8.000000, 8.000000) scale(-1, 1) rotate(-270.000000) translate(-8.000000, -8.000000) translate(3.000000, 5.500000)\"\n fill=\"#71757F\"\n fill-rule=\"nonzero\"\n >\n <path\n d=\"M-0.353553391,-0.353553391 C-0.179987039,-0.527119742 0.0894373624,-0.546404893 0.284305503,-0.411408841 L0.353553391,-0.353553391 L4.999,4.293 L9.64644661,-0.353553391 C9.82001296,-0.527119742 10.0894374,-0.546404893 10.2843055,-0.411408841 L10.3535534,-0.353553391 C10.5271197,-0.179987039 10.5464049,0.0894373624 10.4114088,0.284305503 L10.3535534,0.353553391 L5.35355339,5.35355339 C5.17998704,5.52711974 4.91056264,5.54640489 4.7156945,5.41140884 L4.64644661,5.35355339 L-0.353553391,0.353553391 C-0.548815536,0.158291245 -0.548815536,-0.158291245 -0.353553391,-0.353553391 Z\"\n id=\"路径\"\n ></path>\n </g>\n </g>\n </svg>\n <svg width=\"16px\" height=\"16px\" viewBox=\"0 0 16 16\" style=\"float: right\" class=\"icon devui-cascader-loading\" *ngIf=\"option._loading\">\n <g stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\">\n <path\n d=\"M8,1 C8.55228475,1 9,1.44771525 9,2 L9,4 C9,4.55228475 8.55228475,5 8,5 C7.44771525,5 7,4.55228475 7,4 L7,2 C7,1.44771525 7.44771525,1 8,1 Z M8,11 C8.55228475,11 9,11.4477153 9,12 L9,14 C9,14.5522847 8.55228475,15 8,15 C7.44771525,15 7,14.5522847 7,14 L7,12 C7,11.4477153 7.44771525,11 8,11 Z M15,8 C15,8.55228475 14.5522847,9 14,9 L12,9 C11.4477153,9 11,8.55228475 11,8 C11,7.44771525 11.4477153,7 12,7 L14,7 C14.5522847,7 15,7.44771525 15,8 Z M5,8 C5,8.55228475 4.55228475,9 4,9 L2,9 C1.44771525,9 1,8.55228475 1,8 C1,7.44771525 1.44771525,7 2,7 L4,7 C4.55228475,7 5,7.44771525 5,8 Z M12.9497475,3.05025253 C13.3402718,3.44077682 13.3402718,4.0739418 12.9497475,4.46446609 L11.5355339,5.87867966 C11.1450096,6.26920395 10.5118446,6.26920395 10.1213203,5.87867966 C9.73079605,5.48815536 9.73079605,4.85499039 10.1213203,4.46446609 L11.5355339,3.05025253 C11.9260582,2.65972824 12.5592232,2.65972824 12.9497475,3.05025253 Z M5.87867966,10.1213203 C6.26920395,10.5118446 6.26920395,11.1450096 5.87867966,11.5355339 L4.46446609,12.9497475 C4.0739418,13.3402718 3.44077682,13.3402718 3.05025253,12.9497475 C2.65972824,12.5592232 2.65972824,11.9260582 3.05025253,11.5355339 L4.46446609,10.1213203 C4.85499039,9.73079605 5.48815536,9.73079605 5.87867966,10.1213203 Z M12.9497475,12.9497475 C12.5592232,13.3402718 11.9260582,13.3402718 11.5355339,12.9497475 L10.1213203,11.5355339 C9.73079605,11.1450096 9.73079605,10.5118446 10.1213203,10.1213203 C10.5118446,9.73079605 11.1450096,9.73079605 11.5355339,10.1213203 L12.9497475,11.5355339 C13.3402718,11.9260582 13.3402718,12.5592232 12.9497475,12.9497475 Z M5.87867966,5.87867966 C5.48815536,6.26920395 4.85499039,6.26920395 4.46446609,5.87867966 L3.05025253,4.46446609 C2.65972824,4.0739418 2.65972824,3.44077682 3.05025253,3.05025253 C3.44077682,2.65972824 4.0739418,2.65972824 4.46446609,3.05025253 L5.87867966,4.46446609 C6.26920395,4.85499039 6.26920395,5.48815536 5.87867966,5.87867966 Z\"\n fill=\"#293040\"\n ></path>\n </g>\n </svg>\n </div>\n</li>\n\n<li *ngIf=\"isLeaf\" role=\"menuitem\" (click)=\"clickLeaf()\" [ngClass]=\"{ disabled: option.disabled, 'devui-leaf-active': option.active }\">\n <div class=\"devui-dropdown-item\">\n <d-checkbox\n *ngIf=\"multiple\"\n class=\"devui-dropdown-item-checkbox\"\n [disabled]=\"option.disabled\"\n [isShowTitle]=\"false\"\n [halfchecked]=\"option.halfChecked\"\n (click)=\"clickCheckbox($event)\"\n [ngModel]=\"option.checked\"\n (ngModelChange)=\"updateValue($event)\"\n [beforeChange]=\"avoidCheckboxChange\"\n ></d-checkbox>\n <i *ngIf=\"option.icon\" class=\"icon {{ option.icon }}\"></i>\n <span class=\"dropdown-item-label\">\n <ng-template\n [ngTemplateOutlet]=\"dropDownItemTemplate || defaultDropdownItemTemplate\"\n [ngTemplateOutletContext]=\"{\n option: option,\n label: option.label\n }\"\n >\n </ng-template>\n </span>\n </div>\n</li>\n\n<ng-template #defaultDropdownItemTemplate let-label=\"label\">\n <span>{{ label }}</span>\n</ng-template>\n","import { ConnectedPosition } from '@angular/cdk/overlay';\r\nimport {\r\n Component,\r\n ElementRef,\r\n EventEmitter,\r\n forwardRef,\r\n HostBinding,\r\n Input,\r\n OnChanges,\r\n OnDestroy,\r\n OnInit,\r\n Output,\r\n SimpleChanges,\r\n TemplateRef,\r\n ViewChild,\r\n} from '@angular/core';\r\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\r\nimport { DropDownAppendToBodyComponent, DropDownDirective } from 'ng-devui/dropdown';\r\nimport { I18nInterface, I18nService } from 'ng-devui/i18n';\r\nimport { DevConfigService, WithConfig } from 'ng-devui/utils';\r\nimport { Observable, Subject, Subscription } from 'rxjs';\r\nimport { debounceTime, distinctUntilChanged, filter, takeUntil } from 'rxjs/operators';\r\nimport { CascaderService } from './cascader.service';\r\nimport { CascaderItem } from './cascader.type';\r\n\r\nconst DEBOUNCE_TIME = 200;\r\n\r\n@Component({\r\n selector: 'd-cascader',\r\n templateUrl: './cascader.component.html',\r\n styleUrls: ['./cascader.component.scss'],\r\n providers: [\r\n {\r\n provide: NG_VALUE_ACCESSOR,\r\n useExisting: forwardRef(() => CascaderComponent),\r\n multi: true,\r\n },\r\n CascaderService,\r\n ],\r\n preserveWhitespaces: false,\r\n})\r\nexport class CascaderComponent implements OnInit, OnDestroy, OnChanges, ControlValueAccessor {\r\n @ViewChild('mainDropdown') mainDropdown: DropDownDirective;\r\n @ViewChild('innerInput') innerInput: ElementRef;\r\n @ViewChild('outerInput') outerInput: ElementRef;\r\n @ViewChild(DropDownAppendToBodyComponent, { static: false }) dropdownComp: DropDownAppendToBodyComponent;\r\n @Input() options: CascaderItem[] = [];\r\n @Input() width = 200;\r\n @Input() dropdownWidth: number;\r\n @Input() placeholder = '';\r\n @Input() trigger: 'click' | 'hover' = 'hover';\r\n @Input() disabled = false;\r\n @Input() multiple = false;\r\n @Input() showPath = false;\r\n @Input() allowClear = false;\r\n @Input() allowSearch = false;\r\n @Input() canSelectParent = false;\r\n @Input() checkboxRelation = { upward: true, downward: true };\r\n @Input() dropDownItemTemplate: TemplateRef<any>;\r\n @Input() dropdownHeaderTemplate: TemplateRef<any>;\r\n @Input() hostTemplate: TemplateRef<any>;\r\n @Input() dropdownPanelClass = '';\r\n @Input() appendToBody = true;\r\n @Input() tagMaxWidth = '200px';\r\n @Input() @WithConfig() showAnimation = true;\r\n @Input() @WithConfig() styleType = 'default';\r\n @Input()\r\n set loadChildrenFn(fn: (value: CascaderItem) => Promise<CascaderItem[]> | Observable<CascaderItem[]>) {\r\n this.isLazyLoad = !!fn;\r\n if (fn) {\r\n this.cascaderSrv.loadChildrenFn = fn;\r\n }\r\n }\r\n @Output() toggleEvent = new EventEmitter<boolean>();\r\n\r\n @Input() @WithConfig() showGlowStyle = true;\r\n @HostBinding('class.devui-glow-style') get hasGlowStyle() {\r\n return this.showGlowStyle;\r\n }\r\n\r\n subMenuDirections: ConnectedPosition[] = [\r\n {\r\n originX: 'start',\r\n originY: 'bottom',\r\n overlayX: 'start',\r\n overlayY: 'top',\r\n offsetX: 0,\r\n },\r\n {\r\n originX: 'start',\r\n originY: 'top',\r\n overlayX: 'start',\r\n overlayY: 'bottom',\r\n offsetX: 0,\r\n },\r\n ];\r\n\r\n isLazyLoad: boolean;\r\n\r\n unsubscribe$ = new Subject<void>();\r\n\r\n searchValueChange = new Subject<string>();\r\n\r\n multipleValueList: CascaderItem[] = [];\r\n lazyloadValue = [];\r\n\r\n timer;\r\n showTextValue;\r\n showSearchPanel: boolean;\r\n showSearchInput = false;\r\n onChange = Function.prototype;\r\n onTouched = Function.prototype;\r\n\r\n get columnList() {\r\n return this.cascaderSrv.columnList;\r\n }\r\n\r\n get searchResultList() {\r\n return this.cascaderSrv.searchResultList;\r\n }\r\n\r\n i18nCommonText: I18nInterface['common'];\r\n i18nSubscription: Subscription;\r\n\r\n constructor(private cascaderSrv: CascaderService, private i18n: I18nService, private devConfigService: DevConfigService) {}\r\n\r\n // 获取整颗树的公共方法\r\n public getOptionTree(): CascaderItem[] {\r\n return this.cascaderSrv.options;\r\n }\r\n\r\n ngOnInit() {\r\n this.dropdownWidth = this.dropdownWidth ? this.dropdownWidth : this.width;\r\n this.cascaderSrv.canSelectParent = this.canSelectParent;\r\n this.cascaderSrv.initOptions(this.options);\r\n this.cascaderSrv.isMultiple = this.multiple;\r\n this.cascaderSrv.isLazyLoad = this.isLazyLoad;\r\n this.cascaderSrv.checkboxRelation = this.checkboxRelation;\r\n this.initObservale();\r\n this.initI18n();\r\n }\r\n\r\n ngOnChanges(changes: SimpleChanges) {\r\n const { options, canSelectParent } = changes;\r\n if (options && !options.firstChange) {\r\n this.cascaderSrv.initOptions(this.options);\r\n } else if (canSelectParent && !canSelectParent.firstChange) {\r\n this.cascaderSrv.canSelectParent = this.canSelectParent;\r\n }\r\n }\r\n\r\n initI18n(): void {\r\n this.i18nCommonText = this.i18n.getI18nText().common;\r\n this.i18nSubscription = this.i18n.langChange().subscribe((data) => {\r\n this.i18nCommonText = data.common;\r\n });\r\n }\r\n\r\n valueChanges(value: string): void {\r\n this.searchValueChange.next(value);\r\n }\r\n\r\n chooseSearchResult(option): void {\r\n if (option.checked) {\r\n return;\r\n }\r\n if (this.multiple) {\r\n // 多选模式下更新数据后需要刷新dropdown位置和重新聚焦input\r\n option.checked = true;\r\n this.writeValue([...this.cascaderSrv.multipleValue, option.valueList]);\r\n this.onChange(this.cascaderSrv.multipleValue);\r\n this.mainDropdown.updateCdkConnectedOverlayOrigin();\r\n if (this.innerInput) {\r\n this.innerInput.nativeElement.focus();\r\n }\r\n } else {\r\n this.writeValue(option.valueList);\r\n this.onChange(option.valueList);\r\n this.mainDropdown.isOpen = false;\r\n }\r\n }\r\n\r\n initObservale(): void {\r\n this.cascaderSrv.closeMianDropdown.pipe(takeUntil(this.unsubscribe$)).subscribe((res) => {\r\n if (this.mainDropdown) {\r\n this.mainDropdown.isOpen = false;\r\n }\r\n });\r\n\r\n this.cascaderSrv.currentValueChange.pipe(takeUntil(this.unsubscribe$)).subscribe((res) => {\r\n this.writeValue(res);\r\n this.onChange(res);\r\n });\r\n\r\n this.cascaderSrv.openDrawer.pipe(takeUntil(this.unsubscribe$)).subscribe((res) => {\r\n this.rePosition();\r\n });\r\n\r\n if (this.multiple) {\r\n this.cascaderSrv.updateTagList.pipe(takeUntil(this.unsubscribe$)).subscribe((res) => {\r\n const targetIndex = this.multipleValueList.findIndex((t) => t.value === res.option.value);\r\n if (res.isAdd) {\r\n if (targetIndex === -1) {\r\n this.multipleValueList.push(res.option);\r\n this.updateMultipleValuePathList();\r\n }\r\n } else if (targetIndex !== -1) {\r\n this.multipleValueList.splice(targetIndex, 1);\r\n }\r\n\r\n if (res.isEmit) {\r\n this.onChange(this.cascaderSrv.currentMultipleValue);\r\n }\r\n\r\n // 当taglist变化导致input高度变化时,更新相对位置\r\n setTimeout(() => {\r\n this.mainDropdown.updateCdkConnectedOverlayOrigin();\r\n });\r\n });\r\n }\r\n\r\n if (this.allowSearch) {\r\n this.searchValueChange\r\n .pipe(\r\n takeUntil(this.unsubscribe$),\r\n debounceTime(DEBOUNCE_TIME),\r\n distinctUntilChanged(),\r\n filter((t) => t !== '')\r\n )\r\n .subscribe((value) => {\r\n clearTimeout(this.timer);\r\n if (this.mainDropdown && !this.mainDropdown.isOpen) {\r\n this.mainDropdown.isOpen = true;\r\n }\r\n\r\n if (this.multiple && this.innerInput) {\r\n this.innerInput.nativeElement.focus();\r\n }\r\n this.cascaderSrv.searchResultList = [];\r\n this.cascaderSrv.searchByString(value);\r\n this.showSearchPanel = true;\r\n });\r\n }\r\n\r\n if (this.isLazyLoad) {\r\n this.cascaderSrv.updateShowText.pipe(takeUntil(this.unsubscribe$)).subscribe(() => {\r\n if (this.multiple) {\r\n this.multipleValueList = this.getMultipleValueFromValueList(this.lazyloadValue);\r\n this.cascaderSrv.multipleValue = this.lazyloadValue;\r\n } else {\r\n this.showTextValue = this.showPath\r\n ? this.getPathLabelFormValue(this.cascaderSrv._currentValue)\r\n : this.getLabelFromValue(this.cascaderSrv._currentValue);\r\n }\r\n });\r\n }\r\n }\r\n\r\n deleteTag(tagEvent, option: CascaderItem): void {\r\n tagEvent.event.stopPropagation();\r\n this.cascaderSrv.updateOptionCheckedStatus(option.value, false, this.checkboxRelation.upward, this.checkboxRelation.downward);\r\n this.multipleValueList = this.multipleValueList.filter((t) => t.value !== option.value);\r\n this.onChange(this.cascaderSrv.currentMultipleValue);\r\n // 当taglist变化导致input高度变化时,更新相对位置\r\n setTimeout(() => {\r\n this.mainDropdown.updateCdkConnectedOverlayOrigin();\r\n });\r\n }\r\n\r\n registerOnChange(fn: () => {}): void {\r\n this.onChange = fn;\r\n }\r\n\r\n registerOnTouched(fn: () => {}): void {\r\n this.onTouched = fn;\r\n }\r\n\r\n writeValue(value: Array<number | string> | Array<number | string>[]): void {\r\n if (!this.multiple) {\r\n if (!value) {\r\n this.showTextValue = '';\r\n } else {\r\n this.showTextValue = this.showPath\r\n ? this.getPathLabelFormValue(value as Array<number | string>)\r\n : this.getLabelFromValue(value as Array<number | string>);\r\n this.cascaderSrv._currentValue = value as Array<number | string>;\r\n this.cascaderSrv.updateOptionByValue();\r\n }\r\n } else {\r\n if (!value) {\r\n this.multipleValueList = [];\r\n } else {\r\n this.cascaderSrv.currentMultipleValue = value as Array<number | string>[];\r\n this.lazyloadValue = value;\r\n this.multipleValueList = this.getMultipleValueFromValueList(value as Array<number | string>[]);\r\n this.updateMultipleValuePathList();\r\n }\r\n }\r\n }\r\n\r\n updateMultipleValuePathList() {\r\n if (!this.showPath) {\r\n return;\r\n }\r\n const valueList = this.cascaderSrv.currentMultipleValue;\r\n valueList.forEach((item, index) => {\r\n const value = item[item.length - 1];\r\n const target = this.multipleValueList.find((t) => t.value === value);\r\n if (target) {\r\n target.pathLabel = this.getPathLabelFormValue(item);\r\n }\r\n });\r\n }\r\n\r\n // 从路径数组中获取所有tag的值,并让对应checkbox激活\r\n getMultipleValueFromValueList(valueList: Array<number | string>[]): CascaderItem[] {\r\n const targetList = [];\r\n valueList.forEach((value) => {\r\n let cur: CascaderItem;\r\n let cacheTarget: CascaderItem;\r\n let list = this.cascaderSrv.options;\r\n for (let i = 0; i < value.length; i++) {\r\n cur = list.find((l) => l.value === value[i]);\r\n cacheTarget = cur;\r\n if (this.isLazyLoad && cur && !cur.children?.length && !cur.isLeaf) {\r\n this.cascaderSrv.lazyloadMultipleChild(cur, i);\r\n break;\r\n } else {\r\n list = (cur && cur.children) || [];\r\n }\r\n }\r\n if (cur && cur.isLeaf) {\r\n targetList.push(cur);\r\n cacheTarget = null;\r\n this.cascaderSrv.updateOptionCheckedStatus(cur.value, true, this.checkboxRelation.upward, this.checkboxRelation.downward);\r\n }\r\n\r\n if (cacheTarget) {\r\n targetList.push(cacheTarget);\r\n this.cascaderSrv.updateOptionCheckedStatus(cacheTarget.value, true, this.checkboxRelation.upward, this.checkboxRelation.downward);\r\n }\r\n });\r\n\r\n return targetList;\r\n }\r\n\r\n // 获取路径末的label\r\n getLabelFromValue(value: Array<number | string>): string {\r\n let cur;\r\n let list = this.cascaderSrv.options;\r\n value.forEach((item) => {\r\n cur = list.find((t) => t.value === item) || '';\r\n list = cur.children || [];\r\n });\r\n\r\n return (cur && cur.label) || '';\r\n }\r\n\r\n // 将value数组转换为路径字符串\r\n getPathLabelFormValue(value: Array<number | string>): string {\r\n let path = '';\r\n let cur;\r\n let list = this.cascaderSrv.options;\r\n\r\n value.forEach((item, index) => {\r\n cur = list.find((t) => t.value === item) || '';\r\n if (cur) {\r\n path = path === '' ? path + cur.label : path + ' / ' + cur.label;\r\n } else if (this.cascaderSrv.columnList.length === index + 1) {\r\n path = path === '' ? path + item : path + ' / ' + item;\r\n }\r\n list = cur.children || [];\r\n });\r\n\r\n return path;\r\n }\r\n\r\n clearTags(): void {\r\n if (this.multiple) {\r\n this.multipleValueList = [];\r\n this.cascaderSrv.resetStatus.next();\r\n this.cascaderSrv.resetNodeStatus();\r\n this.cascaderSrv.currentMultipleValue = [];\r\n } else {\r\n this.cascaderSrv.currentValue = [];\r\n }\r\n this.onChange([]);\r\n }\r\n\r\n onToggle(isOpen: boolean): void {\r\n this.toggleEvent.emit(isOpen);\r\n if (isOpen && this.multiple) {\r\n this.cascaderSrv.clearTargetActive(this.cascaderSrv.options.find((t) => t.active));\r\n this.cascaderSrv.columnList.splice(1);\r\n if (this.innerInput) {\r\n this.innerInput.nativeElement.focus();\r\n }\r\n }\r\n\r\n if (isOpen && !this.multiple && this.allowSearch) {\r\n this.outerInput.nativeElement.focus();\r\n }\r\n\r\n if (!isOpen && this.allowSearch) {\r\n if (!this.cascaderSrv.currentValue.length) {\r\n this.showTextValue = null;\r\n } else {\r\n this.writeValue(this.cascaderSrv.currentValue);\r\n }\r\n // 在动画结束后再设置参数,防止panel中内容突变,动画时间200\r\n this.timer = setTimeout(() => {\r\n this.showSearchPanel = false;\r\n }, 200);\r\n }\r\n\r\n if (isOpen) {\r\n this.rePosition();\r\n }\r\n }\r\n\r\n // 防止位置超出overlay边界\r\n rePosition(): void {\r\n if (typeof window === undefined || !this.appendToBody) {\r\n return;\r\n }\r\n setTimeout(() => {\r\n this.dropdownComp.reposition();\r\n const width = this.dropdownComp.overlay.overlayRef?.overlayElement.clientWidth;\r\n const offsetX = this.dropdownComp.overlay.overlayRef?.overlayElement.offsetLeft;\r\n const offsetRight = window.innerWidth - width - offsetX - 20;\r\n this.subMenuDirections.forEach((t) => {\r\n t.offsetX = offsetRight < 0 ? offsetRight : 0;\r\n });\r\n this.dropdownComp.reposition();\r\n }, 0);\r\n }\r\n\r\n ngOnDestroy(): void {\r\n this.unsubscribe$.next();\r\n this.unsubscribe$.complete();\r\n this.searchValueChange.complete();\r\n }\r\n}\r\n","<div\r\n [ngStyle]=\"{ width: width + 'px' }\"\r\n *ngIf=\"appendToBody\"\r\n dDropDown\r\n appendToBody\r\n [trigger]=\"disabled ? 'manually' : 'click'\"\r\n [closeScope]=\"'blank'\"\r\n #mainDropdown=\"d-dropdown\"\r\n (toggleEvent)=\"onToggle($event)\"\r\n [showAnimation]=\"showAnimation\"\r\n [appendToBodyDirections]=\"subMenuDirections\"\r\n [ngClass]=\"{ 'dropdown-show-clear': allowClear && (showTextValue || multipleValueList.length) }\"\r\n>\r\n <div dDropDownToggle (focus)=\"showSearchInput = true\" [class.devui-gray-style]=\"styleType === 'gray'\">\r\n <ng-template\r\n [ngTemplateOutlet]=\"hostTemplate || default\"\r\n [ngTemplateOutletContext]=\"{ value: showTextValue || multipleValueList }\"\r\n ></ng-template>\r\n </div>\r\n\r\n <ng-template #default>\r\n <input\r\n *ngIf=\"!multiple\"\r\n #outerInput\r\n [placeholder]=\"placeholder\"\r\n type=\"text\"\r\n class=\"devui-form-control devui-select-input devui-input\"\r\n [ngClass]=\"{ 'devui-search-cascader': allowSearch }\"\r\n [readonly]=\"!allowSearch\"\r\n [disabled]=\"disabled\"\r\n [ngModel]=\"showTextValue\"\r\n (ngModelChange)=\"valueChanges($event)\"\r\n />\r\n <div class=\"devui-tags-input-wrapper\" *ngIf=\"multiple\">\r\n <div class=\"devui-tags-input devui-scrollbar\">\r\n <d-tag\r\n *ngFor=\"let item of multipleValueList; let index = index\"\r\n [tag]=\"item.pathLabel || item.label\"\r\n [labelStyle]=\"item.disabled ? 'tag-disabled' : ''\"\r\n [deletable]=\"!item.disabled\"\r\n (tagDelete)=\"deleteTag($event, item)\"\r\n [maxWidth]=\"tagMaxWidth\"\r\n ></d-tag>\r\n <input\r\n #innerInput\r\n (blur)=\"showSearchInput = false\"\r\n *ngIf=\"allowSearch && showSearchInput\"\r\n dTextInput\r\n class=\"inner-input\"\r\n [placeholder]=\"multipleValueList.length ? '' : placeholder\"\r\n [ngModel]=\"showTextValue\"\r\n (ngModelChange)=\"valueChanges($event)\"\r\n />\r\n <span *ngIf=\"!multipleValueList.length && !allowSearch\" class=\"devui-dropdown-placeholder\">{{ placeholder }}</span>\r\n </div>\r\n <div class=\"devui-drop-icon-wrapper\">\r\n <span class=\"devui-drop-icon\" [ngClass]=\"{ 'devui-drop-icon-animation': showAnimation }\">\r\n <svg\r\n width=\"16px\"\r\n height=\"16px\"\r\n viewBox=\"0 0 16 16\"\r\n version=\"1.1\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\r\n >\r\n <g stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\">\r\n <path\r\n d=\"M3.64644661,5.64644661 C3.82001296,5.47288026 4.08943736,5.45359511 4.2843055,5.58859116 L4.35355339,5.64644661 L8,9.293 L11.6464466,5.64644661 C11.820013,5.47288026 12.0894374,5.45359511 12.2843055,5.58859116 L12.3535534,5.64644661 C12.5271197,5.82001296 12.5464049,6.08943736 12.4114088,6.2843055 L12.3535534,6.35355339 L8.35355339,10.3535534 C8.17998704,10.5271197 7.91056264,10.5464049 7.7156945,10.4114088 L7.64644661,10.3535534 L3.64644661,6.35355339 C3.45118446,6.15829124 3.45118446,5.84170876 3.64644661,5.64644661 Z\"\r\n ></path>\r\n </g>\r\n </svg>\r\n </span>\r\n <span class=\"devui-cascader-close-icon\" (click)=\"clearTags()\">\r\n <svg\r\n width=\"12px\"\r\n height=\"12px\"\r\n viewBox=\"0 0 12 12\"\r\n version=\"1.1\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\r\n >\r\n <g stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\">\r\n <path\r\n d=\"M8.86785321,3.13214679 C9.02624037,3.29053395 9.02624037,3.54733027 8.86785321,3.70571743 L6.573,6 L8.86785321,8.29428257 C9.02624037,8.45266973 9.02624037,8.70946605 8.86785321,8.86785321 C8.70946605,9.02624037 8.45266973,9.02624037 8.29428257,8.86785321 L6,6.573 L3.70571743,8.86785321 C3.54733027,9.02624037 3.29053395,9.02624037 3.13214679,8.86785321 C2.97375963,8.70946605 2.97375963,8.45266973 3.13214679,8.29428257 L5.427,6 L3.13214679,3.70571743 C2.97375963,3.54733027 2.97375963,3.29053395 3.13214679,3.13214679 C3.29053395,2.97375963 3.54733027,2.97375963 3.70571743,3.13214679 L6,5.427 L8.29428257,3.13214679 C8.45266973,2.97375963 8.70946605,2.97375963 8.86785321,3.13214679 Z\"\r\n fill-rule=\"nonzero\"\r\n ></path>\r\n </g>\r\n </svg>\r\n </span>\r\n </div>\r\n </div>\r\n <div class=\"devui-single-drop-icon-wrapper\" *ngIf=\"!multiple\">\r\n <span class=\"devui-drop-icon\" [ngClass]=\"{ 'devui-drop-icon-animation': showAnimation }\">\r\n <svg\r\n width=\"16px\"\r\n height=\"16px\"\r\n viewBox=\"0 0 16 16\"\r\n version=\"1.1\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\r\n >\r\n <g stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\">\r\n <path\r\n d=\"M3.64644661,5.64644661 C3.82001296,5.47288026 4.08943736,5.45359511 4.2843055,5.58859116 L4.35355339,5.64644661 L8,9.293 L11.6464466,5.64644661 C11.820013,5.47288026 12.0894374,5.45359511 12.2843055,5.58859116 L12.3535534,5.64644661 C12.5271197,5.82001296 12.5464049,6.08943736 12.4114088,6.2843055 L12.3535534,6.35355339 L8.35355339,10.3535534 C8.17998704,10.5271197 7.91056264,10.5464049 7.7156945,10.4114088 L7.64644661,10.3535534 L3.64644661,6.35355339 C3.45118446,6.15829124 3.45118446,5.84170876 3.64644661,5.64644661 Z\"\r\n ></path>\r\n </g>\r\n </svg>\r\n </span>\r\n <span class=\"devui-cascader-close-icon\" (click)=\"clearTags()\">\r\n <svg\r\n width=\"12px\"\r\n height=\"12px\"\r\n viewBox=\"0 0 12 12\"\r\n version=\"1.1\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\r\n >\r\n <g stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\">\r\n <path\r\n d=\"M8.86785321,3.13214679 C9.02624037,3.29053395 9.02624037,3.54733027 8.86785321,3.70571743 L6.573,6 L8.86785321,8.29428257 C9.02624037,8.45266973 9.02624037,8.70946605 8.86785321,8.86785321 C8.70946605,9.02624037 8.45266973,9.02624037 8.29428257,8.86785321 L6,6.573 L3.70571743,8.86785321 C3.54733027,9.02624037 3.29053395,9.02624037 3.13214679,8.86785321 C2.97375963,8.70946605 2.97375963,8.45266973 3.13214679,8.29428257 L5.427,6 L3.13214679,3.70571743 C2.97375963,3.54733027 2.97375963,3.29053395 3.13214679,3.13214679 C3.29053395,2.97375963 3.54733027,2.97375963 3.70571743,3.13214679 L6,5.427 L8.29428257,3.13214679 C8.45266973,2.97375963 8.70946605,2.97375963 8.86785321,3.13214679 Z\"\r\n fill-rule=\"nonzero\"\r\n ></path>\r\n </g>\r\n </svg>\r\n </span>\r\n </div>\r\n </ng-template>\r\n\r\n <div dDropDownMenu class=\"devui-drop-menu-wrapper {{ dropdownPanelClass }}\">\r\n <ng-container *ngIf=\"!showSearchPanel\">\r\n <ul\r\n *ngFor=\"let optionList of columnList; let i = index\"\r\n class=\"devui-cascader-list devui-scrollbar\"\r\n [ngClass]=\"{ 'devui-drop-no-data': !options.length }\"\r\n [ngStyle]=\"{ width: dropdownWidth + 'px' }\"\r\n role=\"menu\"\r\n (click)=\"$event.stopPropagation()\"\r\n >\r\n <ng-container *ngIf=\"dropdownHeaderTemplate\">\r\n <ng-template [ngTemplateOutlet]=\"dropdownHeaderTemplate\" [ngTemplateOutletContext]=\"{ index: i }\"> </ng-template>\r\n </ng-container>\r\n\r\n <ng-container *ngIf=\"optionList.length\">\r\n <d-cascader-li\r\n *ngFor=\"let option of optionList\"\r\n [option]=\"option\"\r\n [trigger]=\"trigger\"\r\n [width]=\"dropdownWidth\"\r\n [multiple]=\"multiple\"\r\n [colIndex]=\"i\"\r\n [dropDownItemTemplate]=\"dropDownItemTemplate\"\r\n [isLazyLoad]=\"isLazyLoad\"\r\n [canSelectParent]=\"canSelectParent\"\r\n [checkboxRelation]=\"checkboxRelation\"\r\n ></d-cascader-li>\r\n </ng-container>\r\n <div *ngIf=\"!optionList.length\" class=\"devui-no-data-tip\">{{ i18nCommonText.noData }}</div>\r\n </ul>\r\n </ng-container>\r\n\r\n <ng-container *ngIf=\"showSearchPanel\">\r\n <ul\r\n class=\"devui-cascader-list devui-scrollbar\"\r\n [style.minWidth]=\"dropdownWidth - 2 + 'px'\"\r\n [ngClass]=\"{ 'devui-drop-no-data': !searchResultList.length }\"\r\n >\r\n <li\r\n *ngFor=\"let item of searchResultList\"\r\n class=\"devui-cascader-list-item\"\r\n [ngClass]=\"{ 'active-li': item.checked }\"\r\n (click)=\"chooseSearchResult(item)\"\r\n >\r\n {{ item.label }}\r\n </li>\r\n <div *ngIf=\"!searchResultList.length\" class=\"devui-no-data-tip\">{{ i18nCommonText.noData }}</div>\r\n </ul>\r\n </ng-container>\r\n </div>\r\n</div>\r\n\r\n<div\r\n *ngIf=\"!appendToBody\"\r\n [ngStyle]=\"{ width: width + 'px' }\"\r\n dDropDown\r\n [trigger]=\"'click'\"\r\n [closeScope]=\"'blank'\"\r\n #mainDropdown=\"d-dropdown\"\r\n (toggleEvent)=\"onToggle($event)\"\r\n [showAnimation]=\"showAnimation\"\r\n>\r\n <div dDropDownToggle (focus)=\"showSearchInput = true\">\r\n <ng-template\r\n [ngTemplateOutlet]=\"hostTemplate || default\"\r\n [ngTemplateOutletContext]=\"{ value: showTextValue || multipleValueList }\"\r\n ></ng-template>\r\n </div>\r\n <ng-template #default>\r\n <input\r\n *ngIf=\"!multiple\"\r\n #outerInput\r\n [placeholder]=\"placeholder\"\r\n type=\"text\"\r\n class=\"devui-form-control devui-select-input devui-input\"\r\n [ngClass]=\"{ 'devui-search-cascader': allowSearch }\"\r\n [readonly]=\"!allowSearch\"\r\n [disabled]=\"disabled\"\r\n [ngModel]=\"showTextValue\"\r\n (ngModelChange)=\"valueChanges($event)\"\r\n />\r\n <div class=\"devui-tags-input-wrapper\" *ngIf=\"multiple\">\r\n <div class=\"devui-tags-input devui-scrollbar\">\r\n <d-tag\r\n *ngFor=\"let item of multipleValueList; let index = index\"\r\n [tag]=\"item.label\"\r\n [deletable]=\"true\"\r\n (tagDelete)=\"deleteTag($event, item)\"\r\n ></d-tag>\r\n <input\r\n #innerInput\r\n (blur)=\"showSearchInput = false\"\r\n *ngIf=\"allowSearch && showSearchInput\"\r\n dTextInput\r\n class=\"inner-input\"\r\n [placeholder]=\"multipleValueList.length ? '' : placeholder\"\r\n [ngModel]=\"showTextValue\"\r\n (ngModelChange)=\"valueChanges($event)\"\r\n />\r\n <span *ngIf=\"!multipleValueList.length && !allowSearch\" class=\"devui-dropdown-placeholder\">{{ placeholder }}</span>\r\n </div>\r\n <div class=\"devui-drop-icon-wrapper\">\r\n <span class=\"devui-drop-icon\" [ngClass]=\"{ 'devui-drop-icon-animation': showAnimation }\">\r\n <svg\r\n width=\"16px\"\r\n height=\"16px\"\r\n viewBox=\"0 0 16 16\"\r\n version=\"1.1\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\r\n >\r\n <g stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\">\r\n <path\r\n d=\"M3.64644661,5.64644661 C3.82001296,5.47288026 4.08943736,5.45359511 4.2843055,5.58859116 L4.35355339,5.64644661 L8,9.293 L11.6464466,5.64644661 C11.820013,5.47288026 12.0894374,5.45359511 12.2843055,5.58859116 L12.3535534,5.64644661 C12.5271197,5.82001296 12.5464049,6.08943736 12.4114088,6.2843055 L12.3535534,6.35355339 L8.35355339,10.3535534 C8.17998704,10.5271197 7.91056264,10.5464049 7.7156945,10.4114088 L7.64644661,10.3535534 L3.64644661,6.35355339 C3.45118446,6.15829124 3.45118446,5.84170876 3.64644661,5.64644661 Z\"\r\n ></path>\r\n </g>\r\n </svg>\r\n </span>\r\n <span class=\"devui-cascader-close-icon\" (click)=\"clearTags()\">\r\n <svg\r\n width=\"12px\"\r\n height=\"12px\"\r\n viewBox=\"0 0 12 12\"\r\n version=\"1.1\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\r\n >\r\n <g stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\">\r\n <path\r\n d=\"M8.86785321,3.13214679 C9.02624037,3.29053395 9.02624037,3.54733027 8.86785321,3.70571743 L6.573,6 L8.86785321,8.29428257 C9.02624037,8.45266973 9.02624037,8.70946605 8.86785321,8.86785321 C8.70946605,9.02624037 8.45266973,9.02624037 8.29428257,8.86785321 L6,6.573 L3.70571743,8.86785321 C3.54733027,9.02624037 3.29053395,9.02624037 3.13214679,8.86785321 C2.97375963,8.70946605 2.97375963,8.45266973 3.13214679,8.29428257 L5.427,6 L3.13214679,3.70571743 C2.97375963,3.54733027 2.97375963,3.29053395 3.13214679,3.13214679 C3.29053395,2.97375963 3.54733027,2.97375963 3.70571743,3.13214679 L6,5.427 L8.29428257,3.13214679 C8.45266973,2.97375963 8.70946605,2.97375963 8.86785321,3.13214679 Z\"\r\n fill-rule=\"nonzero\"\r\n ></path>\r\n </g>\r\n </svg>\r\n </span>\r\n </div>\r\n </div>\r\n <div class=\"devui-single-drop-icon-wrapper\" *ngIf=\"!multiple\">\r\n <span class=\"devui-drop-icon\" [ngClass]=\"{ 'devui-drop-icon-animation': showAnimation }\">\r\n <svg\r\n width=\"16px\"\r\n height=\"16px\"\r\n viewBox=\"0 0 16 16\"\r\n version=\"1.1\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n xmlns:xlink=\"http://www.w3.org/1999/xlink\"\r\n >\r\n <g stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\">\r\n <path\r\n d=\"M3.64644661,5.64644661 C3.82001296,5.47288026 4.08943736,5.45359511 4.2843055,5.58859116 L4.35355339,5.64644661 L8,9.293 L11.6464466,5.64644661 C11.820013,5.47288026 12.0894374,5.45359511 12.2843055,5.58859116 L12.3535534,5.64644661 C12.5271197,5.82001296 12.5464049,6.08943736 12.4114088,6.2843055 L12.3535534,6.35355339 L8.35355339,10.3535534 C8.179987