效果图:
<mat-form-field class="mat-block" [formGroup]="dropdownTreeFormGroup">
<mat-label>{{label}}</mat-label>
<input type="text" matInput formControlName="treeNodeName" #treeSelectInput [required]="required" readonly
[matMenuTriggerFor]="menu" #dropDownTreeMenu="matMenuTrigger" (menuOpened)="menuOpened()" >
<mat-menu #menu="matMenu" xPosition="after" >
<div class="tb-user-menu-items meunContent">
<div *ngIf="treeListData.length>0">
<ng-container *ngTemplateOutlet="treeNode;context:{$implicit:treeListData}">
</ng-container>
<ng-template #treeNode let-itemNode>
<ng-container *ngFor="let item of itemNode">
<div mat-menu-item (click)="selectTreeNode($event,item)" class="treeItem"
[ngStyle]="{'padding-left':item.level * 20 + 'px'}">
<button mat-icon-button>
<mat-icon class="material-icons" (click)="handleOpen($event,item)"
*ngIf="item.children&&item.children.length>0">{{
item.open? 'expand_less'
: 'expand_more' }}</mat-icon>
</button>
<span>{{item[renderKey]}}</span>
</div>
<ng-container *ngIf="item.children&&item.children.length>0 && item.open">
<ng-container *ngTemplateOutlet="treeNode;context:{$implicit:item.children}"></ng-container>
</ng-container>
</ng-container>
</ng-template>
</div>
<div *ngIf="treeListData.length==0" class="noDataModal_treeSelect" [fxShow]="showDropDown">
<span>暂无数据</span>
</div>
</div>
</mat-menu>
</mat-form-field>
ts:
import { Component, Input, OnInit, ViewChild, NgZone, ElementRef, forwardRef, Output, EventEmitter, SimpleChanges, OnChanges } from '@angular/core';
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms';
import { DeviceProfileId } from '@shared/models/id/device-profile-id';
import { Observable, of } from 'rxjs';
import { Direction } from '@shared/models/page/sort-order';
import { map, mergeMap, share, tap, startWith } from 'rxjs/operators';
import { DeviceTypeService } from '@core/http/device-type.service';
import { DeviceProfile, DeviceTypeInfo, DeviceTransportType } from '@shared/models/device.models';
import { PageLink } from '@shared/models/page/page-link';
import { TranslateService } from '@ngx-translate/core';
import { MatMenuTrigger } from '@angular/material/menu';
import * as $ from "jquery"
@Component({
selector: 'tb-dropdown-tree',
templateUrl: './tb-dropdown-tree.component.html',
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => DropDownTreeComponent),
multi: true
}],
styleUrls: ['./tb-dropdown-tree.component.scss']
})
export class DropDownTreeComponent implements ControlValueAccessor, OnInit, OnChanges {
@ViewChild('dropDownTreeMenu', {static: true}) dropDownTreeMenu: MatMenuTrigger;
@Input() itemNode
@Input() required: boolean = false;
@Input() label: string = "";
@Input() placeholder: string = "";
isEditValue = true;//编辑
@Input()
set isEdit(edit: boolean) {
this.isEditValue = edit;
if (this.dropdownTreeFormGroup) {
if (!edit) {
this.dropdownTreeFormGroup.get('treeNodeName').disable({ emitEvent: false }); //设置disable
} else {
this.dropdownTreeFormGroup.get('treeNodeName').enable({ emitEvent: false });//取消disable
}
}
}
get isEdit() {
return this.isEditValue
}
@Input()
set treeList(data) {
if (data && data.length > 0) {
this.treeListData = data;
this.addTreeOpenValue(this.treeListData);//添加open值
}
}
@Input() autocompleteKey: any = "name"; //循环取的key
@Input()
set treeModalValue(nodeValue:string){
if(this.dropdownTreeFormGroup&&nodeValue!=="defaultValve"){
this.dropdownTreeFormGroup.patchValue({treeNodeName:nodeValue})
}
}
@Input()
renderKey = "title";//页面渲染的key值
@Input()
transportType: DeviceTransportType = null;
@Output()
selectOrgNode = new EventEmitter<DeviceTypeInfo>();
@ViewChild('treeSelectInput', { static: true }) treeSelectInput: ElementRef;
dropdownTreeFormGroup: FormGroup;
showDropDown: boolean = false;
private dirty = false;
treeListData = [];//组织树
filteredDeviceTypes: Observable<Array<DeviceTypeInfo>>
private propagateChange = (v: any) => { };
constructor(
private fb: FormBuilder,
private deviceTypeService: DeviceTypeService,
public translate: TranslateService,
private zone: NgZone,
) {
this.dropdownTreeFormGroup = this.fb.group({
treeNodeName: [null]
});
}
ngOnInit() {
window.addEventListener('resize', () => {
this.setDropDownStyle();
})
}
menuOpened(){
this.setDropDownStyle();
}
setDropDownStyle() {
let inputWidth = $(this.treeSelectInput.nativeElement).width();
setTimeout(()=>{
$('.mat-menu-panel').css({maxWidth:2000});
$('.cdk-overlay-container').find('.meunContent').css({width: inputWidth});
},10)
}
handleTreeModal($event) {
if ($event) {
$event.stopPropagation();
$event.preventDefault();
}
this.showDropDown = !this.showDropDown;
if(this.showDropDown ){
this.setDropDownStyle();
}
}
selectTreeNode($event, item) {
if ($event) {
$event.stopPropagation();
$event.preventDefault();
}
this.dropdownTreeFormGroup.patchValue({ treeNodeName: item[this.renderKey]})
this.selectOrgNode.emit(item)
this.dropDownTreeMenu.closeMenu()
}
// 数据增加open值
addTreeOpenValue(listData, level = 1) {
for (let item of listData) {
if (item.children && item.children.length > 0) {
this.addTreeOpenValue(item.children, level + 1);
}
item.level = level;
item.open = false;
}
}
handleOpen($event, item) {
if ($event) {
$event.stopPropagation();
$event.preventDefault();
}
item.open = !item.open;
}
registerOnChange(fn: any): void {
this.propagateChange = fn;
}
updateView(deviceProfile: DeviceTypeInfo | null) {
}
ngOnChanges(changes: SimpleChanges): void {
}
writeValue(value: DeviceProfileId | null): void {
}
registerOnTouched(fn: any): void {
}
}
引用
<!-- 下拉组织树 -->
<tb-dropdown-tree label="所属组织" *ngIf="showOrgForm" [treeModalValue]="treeModalValue" [isEdit]="orgTreeIsEdit" (selectOrgNode)="selectOrgNode($event)" [required]="true" [treeList]="treeList"></tb-dropdown-tree>