projects/rebirth-ng/src/lib/tree-view/tree-node.component.ts
exportAs | treeNode |
selector | re-tree-node,[reTreeNode] |
styleUrls | tee-node.component.scss |
templateUrl | ./tee-node.component.html |
Properties |
Methods |
Inputs |
constructor(treeViewComponent: TreeViewComponent, treePanelComponent: TreePanelComponent, renderer: Renderer2)
|
||||||||||||
Parameters :
|
allowDraggable
|
Default value: |
allowMutipleSelected
|
Default value: |
checkable
|
Default value: |
collapseIcon
|
|
expendIcon
|
|
iconField
|
Type: |
lazyLoad
|
Default value: |
leafIcon
|
|
loadChildren
|
Type: |
loadingIcon
|
Type: |
node
|
Type: |
nodeCssClass
|
Type: |
nodeItemTemplate
|
Type: |
nodeItemToolbarTemplate
|
Type: |
parentNode
|
Type: |
textField
|
Type: |
valueField
|
Type: |
Private changeChildrenChecked | |||||||||
changeChildrenChecked(nodes: any[], checked: )
|
|||||||||
Parameters :
Returns :
void
|
getNodeExpendIcon |
getNodeExpendIcon()
|
Returns :
any
|
Private isDescendant | ||||||
isDescendant(parent: , target: )
|
||||||
Parameters :
Returns :
any
|
isLeaf |
isLeaf()
|
Returns :
boolean
|
Private isNodeMyself | ||||||
isNodeMyself(dropData: any)
|
||||||
Parameters :
Returns :
boolean
|
nodeItemCheckedChange | ||||
nodeItemCheckedChange(checked: )
|
||||
Parameters :
Returns :
void
|
onChildrenNodeCheckedChange | ||||
onChildrenNodeCheckedChange(node: )
|
||||
Parameters :
Returns :
void
|
onDragEnter |
onDragEnter()
|
Returns :
void
|
onDragLeave |
onDragLeave()
|
Returns :
void
|
onDropNodeItem | ||||
onDropNodeItem($event: )
|
||||
Parameters :
Returns :
void
|
onExpendedIconClick | ||||
onExpendedIconClick($event: )
|
||||
Parameters :
Returns :
void
|
onNodeItemClick | ||||
onNodeItemClick($event: )
|
||||
Parameters :
Returns :
void
|
onNodeItemDbClicked | ||||
onNodeItemDbClicked($event: )
|
||||
Parameters :
Returns :
void
|
isLoading |
isLoading:
|
Type : boolean
|
nodeItemContent |
nodeItemContent:
|
Type : ElementRef
|
Decorators : ViewChild
|
import { Component, Input, TemplateRef, ViewChild, ElementRef, Renderer2 } from '@angular/core';
import { TreeViewComponent } from './tree-view.component';
import { TreePanelComponent } from './tree-panel.component';
import { Observable, of } from 'rxjs';
import { map } from 'rxjs/operators';
import { DraggableDirective } from '../draggable/draggable.directive';
@Component({
selector: 're-tree-node,[reTreeNode]',
templateUrl: './tee-node.component.html',
styleUrls: ['./tee-node.component.scss'],
exportAs: 'treeNode'
})
export class TreeNodeComponent {
@Input() node: any;
@Input() parentNode: any;
@Input() valueField: string;
@Input() textField: string;
@Input() nodeCssClass: string;
@Input() iconField: string;
@Input() checkable = false;
@Input() lazyLoad = false;
@Input() loadingIcon: string;
@Input() loadChildren: (parent: any) => Observable<any[]>;
@Input() allowDraggable = false;
@Input() allowMutipleSelected = false;
@Input() nodeItemTemplate: TemplateRef<any>;
@Input() nodeItemToolbarTemplate: TemplateRef<any>;
@Input() leafIcon;
@Input() expendIcon;
@Input() collapseIcon;
@ViewChild('nodeItemContent') nodeItemContent: ElementRef;
isLoading: boolean;
isAcceptDrop = ($event) => {
const dropData = JSON.parse($event.dataTransfer.getData(DraggableDirective.DRAGGABLE_DATA_KEY));
if (!dropData.data.node) {
return false;
}
if (this.isNodeMyself(dropData)) {
return false;
}
if (this.isDescendant(dropData.data.node, this.node)) {
return false;
}
return true;
}
constructor(private treeViewComponent: TreeViewComponent,
private treePanelComponent: TreePanelComponent,
private renderer: Renderer2) {
}
getNodeExpendIcon() {
if (this.isLeaf()) {
return this.leafIcon;
}
return this.node.$expend ? this.expendIcon : this.collapseIcon;
}
onExpendedIconClick($event) {
$event.stopPropagation();
if (this.isLeaf() || this.isLoading) {
return;
}
let loadObservable = of(null);
if (this.lazyLoad && !this.node.$loaded) {
this.isLoading = true;
loadObservable = this.loadChildren(this.node)
.pipe(map((children) => {
this.node.children = children || [];
this.node.$loaded = true;
}));
}
loadObservable.subscribe(() => {
this.isLoading = false;
this.node.$expend = !this.node.$expend;
this.treeViewComponent.onNodeItemExpended(this.node);
}, () => {
this.isLoading = false;
});
}
onNodeItemClick($event) {
$event.stopPropagation();
this.node.$select = !this.node.$select;
this.treeViewComponent.onNodeItemClicked(this.node);
}
onNodeItemDbClicked($event) {
this.treeViewComponent.onNodeItemDbClicked(this.node);
}
nodeItemCheckedChange(checked) {
this.changeChildrenChecked(this.node.children, checked);
this.treePanelComponent.onNodeItemCheckedChanged(this.node);
}
onChildrenNodeCheckedChange(node) {
this.node.$check = !this.node.children.some((item) => !item.$check);
this.treePanelComponent.onNodeItemCheckedChanged(node);
}
isLeaf() {
if (this.lazyLoad && !this.node.$loaded) {
return false;
}
return !this.node.children || !this.node.children.length;
}
onDragEnter() {
this.renderer.addClass(this.nodeItemContent.nativeElement, 'drop-node-enter');
}
onDragLeave() {
setTimeout(() => {
this.renderer.removeClass(this.nodeItemContent.nativeElement, 'drop-node-enter');
});
}
onDropNodeItem($event) {
const dropData = JSON.parse($event.dataTransfer.getData(DraggableDirective.DRAGGABLE_DATA_KEY));
if (dropData.data.node && !this.isNodeMyself(dropData)) {
this.treeViewComponent.onNodeItemDroped({ target: this.node, data: dropData });
}
setTimeout(() => {
this.renderer.removeClass(this.nodeItemContent.nativeElement, 'drop-node-enter');
}, 0);
}
private isNodeMyself(dropData: any) {
return this.node[this.valueField] === dropData.data.node[this.valueField];
}
private isDescendant(parent, target) {
if (!parent) {
return false;
}
return (parent.children || []).some((nodeItem) => {
return nodeItem[this.valueField] === target[this.valueField] || this.isDescendant(nodeItem, target);
});
}
private changeChildrenChecked(nodes: any[], checked) {
if (!nodes) {
return;
}
nodes.forEach((node) => {
node.$check = checked;
this.changeChildrenChecked(node.children, checked);
});
}
}
<div class="node-item {{nodeCssClass}}" reDraggable="re:node-item-drop" [disabled]="!allowDraggable"
[dragData]="{node: node, parent: parentNode}">
<div class="node-item-panel">
<i class="node-expend-icon {{getNodeExpendIcon()}}"
(click)="onExpendedIconClick($event)"></i>
<div class="node-item-content" #nodeItemContent reDroppable="re:node-item-drop" (onDrop)="onDropNodeItem($event)"
(onDragEnter)="onDragEnter()" (onDragLeave)="onDragLeave()" [acceptDrop]="isAcceptDrop">
<div class="node-check-box">
<re-checkbox *ngIf="checkable" [(ngModel)]="node.$check" label=""
(valueChange)="nodeItemCheckedChange($event)"></re-checkbox>
</div>
<ng-container *ngIf="!nodeItemTemplate">
<span class="node-text" [ngClass]="{'bg-primary': node.$select}" (click)="onNodeItemClick($event)"
(dblclick)="onNodeItemDbClicked($event)">
<i *ngIf="iconField && node[iconField]"
class="node-icon {{node[iconField]}}"></i> {{node[textField] || ''}} <span
class="loading" *ngIf="isLoading">
<i class="{{loadingIcon}}"></i></span>
</span>
<div class="toolbar">
<ng-template *ngIf="nodeItemToolbarTemplate" [ngTemplateOutlet]="nodeItemToolbarTemplate"
[ngTemplateOutletContext]="{$implicit: node, parentNode:parentNode, tree: this}"></ng-template>
</div>
</ng-container>
<ng-container *ngIf="nodeItemTemplate">
<ng-template *ngIf="nodeItemTemplate" [ngTemplateOutlet]="nodeItemTemplate"
[ngTemplateOutletContext]="{$implicit: node, parentNode:parentNode, tree: this }"></ng-template>
</ng-container>
</div>
</div>
<re-tree-panel *ngIf="node.children && node.children.length && node.$expend"
class="children-view"
[treeData]="node.children"
[textField]="textField"
[valueField]="valueField"
[iconField]="iconField"
[checkable]="checkable"
[lazyLoad]="lazyLoad"
[loadingIcon]="loadingIcon"
[loadChildren]="loadChildren"
[allowDraggable]="allowDraggable"
[allowMutipleSelected]="allowMutipleSelected"
[parentNode]="node"
[nodeItemTemplate]="nodeItemTemplate"
[nodeItemToolbarTemplate]="nodeItemToolbarTemplate"
[leafIcon]="leafIcon"
[expendIcon]="expendIcon"
[collapseIcon]="collapseIcon"
(nodeItemCheckedChanged)="onChildrenNodeCheckedChange($event)"
></re-tree-panel>
</div>