diff --git a/src/demo/app/app.component.ts b/src/demo/app/app.component.ts index e335df66..92cf53ac 100644 --- a/src/demo/app/app.component.ts +++ b/src/demo/app/app.component.ts @@ -31,7 +31,7 @@ declare const alertify: any;
+ (nodeCollapsed)="onNodeCollapsed($event)" + [settings]="settings">
@@ -79,6 +80,9 @@ declare const alertify: any; + +
@@ -175,9 +179,17 @@ declare const alertify: any; }) export class AppComponent implements OnInit { public settings: Ng2TreeSettings = { - rootIsVisible: false + rootIsVisible: false, + showCheckboxes: true, + }; + + public disabledCheckboxesSettings: Ng2TreeSettings = { + rootIsVisible: false, + showCheckboxes: true, + enableCheckboxes: false }; + public fonts: TreeModel = { value: 'Fonts', children: [ @@ -188,18 +200,18 @@ export class AppComponent implements OnInit { 'static': true }, children: [ - {value: 'Antiqua with HTML tags.', id: 2}, - {value: 'DejaVu Serif', id: 3}, - {value: 'Garamond', id: 4}, - {value: 'Georgia', id: 5}, - {value: 'Times New Roman', id: 6}, + { value: 'Antiqua with HTML tags.', id: 2 }, + { value: 'DejaVu Serif', id: 3 }, + { value: 'Garamond', id: 4 }, + { value: 'Georgia', id: 5 }, + { value: 'Times New Roman', id: 6 }, { value: 'Slab serif', id: 7, children: [ - {value: 'Candida', id: 8}, - {value: 'Swift', id: 9}, - {value: 'Guardian Egyptian', id: 10} + { value: 'Candida', id: 8 }, + { value: 'Swift', id: 9 }, + { value: 'Guardian Egyptian', id: 10 } ] } ] @@ -215,29 +227,29 @@ export class AppComponent implements OnInit { ] }, children: [ - {value: 'Arial', id: 12}, - {value: 'Century Gothic', id: 13}, - {value: 'DejaVu Sans', id: 14}, - {value: 'Futura', id: 15}, - {value: 'Geneva', id: 16}, - {value: 'Liberation Sans', id: 17} + { value: 'Arial', id: 12 }, + { value: 'Century Gothic', id: 13 }, + { value: 'DejaVu Sans', id: 14 }, + { value: 'Futura', id: 15 }, + { value: 'Geneva', id: 16 }, + { value: 'Liberation Sans', id: 17 } ] }, { value: 'Monospace - With ASYNC CHILDREN', id: 18, // children property is ignored if "loadChildren" is present - children: [{value: 'I am the font that will be ignored'}], + children: [{ value: 'I am the font that will be ignored' }], loadChildren: (callback) => { setTimeout(() => { callback([ - {value: 'Input Mono', id: 19}, - {value: 'Roboto Mono', id: 20}, - {value: 'Liberation Mono', id: 21}, - {value: 'Hack', id: 22}, - {value: 'Consolas', id: 23}, - {value: 'Menlo', id: 24}, - {value: 'Source Code Pro', id: 25} + { value: 'Input Mono', id: 19 }, + { value: 'Roboto Mono', id: 20 }, + { value: 'Liberation Mono', id: 21 }, + { value: 'Hack', id: 22 }, + { value: 'Consolas', id: 23 }, + { value: 'Menlo', id: 24 }, + { value: 'Source Code Pro', id: 25 } ]); }, 5000); } @@ -253,6 +265,7 @@ export class AppComponent implements OnInit { value: '/', id: 1, settings: { + cssClasses: { expanded: 'fa fa-caret-down', collapsed: 'fa fa-caret-right', @@ -269,6 +282,7 @@ export class AppComponent implements OnInit { value: 'bin', id: 2, children: [ + {value: 'bash', id: 3}, {value: 'umount', id: 4}, {value: 'cp', id: 5}, @@ -292,13 +306,13 @@ export class AppComponent implements OnInit { value: 'grub', id: 14, children: [ - {value: 'fonts', id: 15}, - {value: 'gfxblacklist.txt', id: 16}, - {value: 'grub.cfg', id: 17}, - {value: 'grubenv', id: 18}, - {value: 'i386-pc', id: 19}, - {value: 'locale', id: 20}, - {value: 'unicode.pf2', id: 21} + { value: 'fonts', id: 15 }, + { value: 'gfxblacklist.txt', id: 16 }, + { value: 'grub.cfg', id: 17 }, + { value: 'grubenv', id: 18 }, + { value: 'i386-pc', id: 19 }, + { value: 'locale', id: 20 }, + { value: 'unicode.pf2', id: 21 } ] }, { @@ -306,15 +320,15 @@ export class AppComponent implements OnInit { id: 22, children: [] }, - {value: 'abi-4.4.0-57-generic', id: 23}, - {value: 'config-4.4.0-57-generic', id: 24}, - {value: 'initrd.img-4.4.0-47-generic', id: 25}, - {value: 'initrd.img-4.4.0-57-generic', id: 26}, - {value: 'memtest86+.bin', id: 27}, - {value: 'System.map-4.4.0-57-generic', id: 28}, - {value: 'memtest86+.elf', id: 29}, - {value: 'vmlinuz-4.4.0-57-generic', id: 30}, - {value: 'memtest86+_multiboot.bin', id: 31} + { value: 'abi-4.4.0-57-generic', id: 23 }, + { value: 'config-4.4.0-57-generic', id: 24 }, + { value: 'initrd.img-4.4.0-47-generic', id: 25 }, + { value: 'initrd.img-4.4.0-57-generic', id: 26 }, + { value: 'memtest86+.bin', id: 27 }, + { value: 'System.map-4.4.0-57-generic', id: 28 }, + { value: 'memtest86+.elf', id: 29 }, + { value: 'vmlinuz-4.4.0-57-generic', id: 30 }, + { value: 'memtest86+_multiboot.bin', id: 31 } ] }, { @@ -348,8 +362,8 @@ export class AppComponent implements OnInit { } ] }, - {value: 'cdrom', id: 34, children: []}, - {value: 'dev', id: 35, children: []}, + { value: 'cdrom', id: 34, children: [] }, + { value: 'dev', id: 35, children: [] }, { value: 'etc', id: 36, @@ -357,10 +371,10 @@ export class AppComponent implements OnInit { console.log('callback function called to load etc`s children'); setTimeout(() => { callback([ - {value: 'apache2', id: 82, children: []}, - {value: 'nginx', id: 83, children: []}, - {value: 'dhcp', id: 84, children: []}, - {value: 'dpkg', id: 85, children: []} + { value: 'apache2', id: 82, children: [] }, + { value: 'nginx', id: 83, children: [] }, + { value: 'dhcp', id: 84, children: [] }, + { value: 'dpkg', id: 85, children: [] } ]); }); } @@ -385,38 +399,38 @@ export class AppComponent implements OnInit { value: 'bills', id: 41, children: [ - {value: '2016-07-01-mobile.pdf', id: 42}, - {value: '2016-07-01-electricity.pdf', id: 43}, - {value: '2016-07-01-water.pdf', id: 44}, - {value: '2016-07-01-internet.pdf', id: 45}, - {value: '2016-08-01-mobile.pdf', id: 46}, - {value: '2016-10-01-internet.pdf', id: 47} + { value: '2016-07-01-mobile.pdf', id: 42 }, + { value: '2016-07-01-electricity.pdf', id: 43 }, + { value: '2016-07-01-water.pdf', id: 44 }, + { value: '2016-07-01-internet.pdf', id: 45 }, + { value: '2016-08-01-mobile.pdf', id: 46 }, + { value: '2016-10-01-internet.pdf', id: 47 } ] }, - {value: 'photos', id: 48, children: []} + { value: 'photos', id: 48, children: [] } ] } ] }, - {value: 'Downloads', id: 49, children: []}, - {value: 'Desktop', id: 50, children: []}, - {value: 'Pictures', id: 51, children: []}, + { value: 'Downloads', id: 49, children: [] }, + { value: 'Desktop', id: 50, children: [] }, + { value: 'Pictures', id: 51, children: [] }, { value: 'Music', id: 52, - children: [{value: 'won\'t be displayed'}], + children: [{ value: 'won\'t be displayed' }], loadChildren: (callback) => { setTimeout(() => { callback([ - {value: '2Cellos', id: 78, children: []}, - {value: 'Michael Jackson', id: 79, children: []}, - {value: 'AC/DC', id: 80, children: []}, - {value: 'Adel', id: 81, children: []} + { value: '2Cellos', id: 78, children: [] }, + { value: 'Michael Jackson', id: 79, children: [] }, + { value: 'AC/DC', id: 80, children: [] }, + { value: 'Adel', id: 81, children: [] } ]); }, 5000); } }, - {value: 'Public', id: 53, children: []} + { value: 'Public', id: 53, children: [] } ] }, { @@ -426,7 +440,7 @@ export class AppComponent implements OnInit { leftMenu: true }, children: [ - {value: 'Documents', id: 55, children: []}, + { value: 'Documents', id: 55, children: [] }, { value: 'Downloads - custom left menu template', id: 56, @@ -436,33 +450,33 @@ export class AppComponent implements OnInit { } }, children: [ - {value: 'Actobat3', id: 57}, - {value: 'Complib', id: 58}, - {value: 'Eudora', id: 59}, - {value: 'java', id: 60}, - {value: 'drivers', id: 61}, - {value: 'kathy', id: 62} + { value: 'Actobat3', id: 57 }, + { value: 'Complib', id: 58 }, + { value: 'Eudora', id: 59 }, + { value: 'java', id: 60 }, + { value: 'drivers', id: 61 }, + { value: 'kathy', id: 62 } ] }, - {value: 'Desktop', id: 63, children: []}, - {value: 'Pictures', id: 64, children: []}, - {value: 'Music', id: 65, children: []}, - {value: 'Public', id: 66, children: []} + { value: 'Desktop', id: 63, children: [] }, + { value: 'Pictures', id: 64, children: [] }, + { value: 'Music', id: 65, children: [] }, + { value: 'Public', id: 66, children: [] } ] } ] }, - {value: 'lib', id: 67, children: []}, - {value: 'media', id: 68, children: []}, - {value: 'opt', id: 69, children: []}, - {value: 'proc', id: 70, children: []}, - {value: 'root', id: 71, children: []}, - {value: 'run', id: 72, children: []}, - {value: 'sbin', id: 73, children: []}, - {value: 'srv', id: 74, children: []}, - {value: 'sys', id: 75, children: []}, - {value: 'usr', id: 76, children: []}, - {value: 'var', id: 77, children: []} + { value: 'lib', id: 67, children: [] }, + { value: 'media', id: 68, children: [] }, + { value: 'opt', id: 69, children: [] }, + { value: 'proc', id: 70, children: [] }, + { value: 'root', id: 71, children: [] }, + { value: 'run', id: 72, children: [] }, + { value: 'sbin', id: 73, children: [] }, + { value: 'srv', id: 74, children: [] }, + { value: 'sys', id: 75, children: [] }, + { value: 'usr', id: 76, children: [] }, + { value: 'var', id: 77, children: [] } ] }; private lastFFSNodeId = 86; @@ -475,31 +489,31 @@ export class AppComponent implements OnInit { { value: 'Web Application Icons', children: [ - {value: 'calendar', icon: 'fa-calendar' }, - {value: 'download', icon: 'fa-download' }, - {value: 'group', icon: 'fa-group' }, - {value: 'print', icon: 'fa-print' } + { value: 'calendar', icon: 'fa-calendar' }, + { value: 'download', icon: 'fa-download' }, + { value: 'group', icon: 'fa-group' }, + { value: 'print', icon: 'fa-print' } ] }, { value: 'Hand Icons', children: [ - {value: 'pointer', icon: 'fa-hand-pointer-o' }, - {value: 'grab', icon: 'fa-hand-rock-o' }, - {value: 'thumbs up', icon: 'fa-thumbs-o-up ' }, - {value: 'thumbs down', icon: 'fa-thumbs-o-down' } + { value: 'pointer', icon: 'fa-hand-pointer-o' }, + { value: 'grab', icon: 'fa-hand-rock-o' }, + { value: 'thumbs up', icon: 'fa-thumbs-o-up ' }, + { value: 'thumbs down', icon: 'fa-thumbs-o-down' } ] }, { value: 'File Type Icons', children: [ - {value: 'file', icon: 'fa-file-o' }, - {value: 'audio', icon: 'fa-file-audio-o' }, - {value: 'movie', icon: 'fa-file-movie-o ' }, - {value: 'archive', icon: 'fa-file-zip-o' } + { value: 'file', icon: 'fa-file-o' }, + { value: 'audio', icon: 'fa-file-audio-o' }, + { value: 'movie', icon: 'fa-file-movie-o ' }, + { value: 'archive', icon: 'fa-file-zip-o' } ] }, - ] + ] }; private static logEvent(e: NodeEvent, message: string): void { @@ -515,8 +529,8 @@ export class AppComponent implements OnInit { { value: 'Aspect-oriented programming', children: [ - {value: 'AspectJ'}, - {value: 'AspectC++'} + { value: 'AspectJ' }, + { value: 'AspectC++' } ] }, { @@ -533,16 +547,16 @@ export class AppComponent implements OnInit { } } as RenamableNode }, - {value: 'C++'}, - {value: 'C#'} + { value: 'C++' }, + { value: 'C#' } ] }, { value: 'Prototype-based programming', children: [ - {value: 'JavaScript'}, - {value: 'CoffeeScript'}, - {value: 'TypeScript'} + { value: 'JavaScript' }, + { value: 'CoffeeScript' }, + { value: 'TypeScript' } ] } ] @@ -611,11 +625,11 @@ export class AppComponent implements OnInit { const treeController = this.treeFFS.getControllerByNodeId(id); if (treeController && typeof treeController.setChildren === 'function') { treeController.setChildren([ - {value: 'apache2', id: 82, children: []}, - {value: 'nginx', id: 83, children: []}, - {value: 'dhcp', id: 84, children: []}, - {value: 'dpkg', id: 85, children: []}, - {value: 'gdb', id: 86, children: []} + { value: 'apache2', id: 82, children: [] }, + { value: 'nginx', id: 83, children: [] }, + { value: 'dhcp', id: 84, children: [] }, + { value: 'dpkg', id: 85, children: [] }, + { value: 'gdb', id: 86, children: [] } ]); } else { console.log('There isn`t a controller for a node with id - ' + id); @@ -631,4 +645,24 @@ export class AppComponent implements OnInit { console.log(`Controller is absent for a node with id: ${id}`); } } + + public checkFolder(id: number): void { + const treeController = this.treeFFS.getControllerByNodeId(id); + if (treeController) { + treeController.check(); + } else { + console.log(`Controller is absent for a node with id: ${id}`); + } + + } + + public uncheckFolder(id: number): void { + const treeController = this.treeFFS.getControllerByNodeId(id); + if (treeController) { + treeController.uncheck(); + } else { + console.log(`Controller is absent for a node with id: ${id}`); + } + + } } diff --git a/src/tree-controller.ts b/src/tree-controller.ts index 86fbe530..ff351f89 100644 --- a/src/tree-controller.ts +++ b/src/tree-controller.ts @@ -92,6 +92,13 @@ export class TreeController { public startRenaming(): void { this.tree.markAsBeingRenamed(); + } - } + public check() : void { + this.component.onNodeChecked() +} + +public uncheck() : void { + this.component.onNodeUnchecked() +} } diff --git a/src/tree-internal.component.ts b/src/tree-internal.component.ts index 874c73fe..d542ba33 100644 --- a/src/tree-internal.component.ts +++ b/src/tree-internal.component.ts @@ -1,3 +1,4 @@ + import { Component, ElementRef, @@ -6,19 +7,22 @@ import { OnDestroy, OnInit, SimpleChanges, - TemplateRef + TemplateRef, + ViewChild } from '@angular/core'; + import * as TreeTypes from './tree.types'; import { Tree } from './tree'; import { TreeController } from './tree-controller'; import { NodeMenuService } from './menu/node-menu.service'; import { NodeMenuItemAction, NodeMenuItemSelectedEvent } from './menu/menu.events'; import { NodeEditableEvent, NodeEditableEventAction } from './editable/editable.events'; +import { NodeEvent, NodeRemovedEvent, NodeCheckedEvent, NodeIndeterminateEvent } from './tree.events' import { TreeService } from './tree.service'; import * as EventUtils from './utils/event.utils'; import { NodeDraggableEvent } from './draggable/draggable.events'; import { Subscription } from 'rxjs/Subscription'; -import { get } from './utils/fn.utils'; +import { get, has } from './utils/fn.utils'; @Component({ selector: 'tree-internal', @@ -33,6 +37,11 @@ import { get } from './utils/fn.utils'; [tree]="tree">
+ +
+ +
+
- @@ -64,7 +73,7 @@ import { get } from './utils/fn.utils'; (menuItemSelected)="onMenuItemSelected($event)"> - + @@ -83,13 +92,20 @@ export class TreeInternalComponent implements OnInit, OnChanges, OnDestroy { public isSelected = false; public isRightMenuVisible = false; public isLeftMenuVisible = false; + public isChecked = false; + public isReadOnly = false; public controller: TreeController; + + @ViewChild('checkbox') + _checkboxElement: ElementRef; + private subscriptions: Subscription[] = []; + public constructor(private nodeMenuService: NodeMenuService, - public treeService: TreeService, - public element: ElementRef) { + public treeService: TreeService, + public element: ElementRef) { } public ngOnInit(): void { @@ -98,7 +114,13 @@ export class TreeInternalComponent implements OnInit, OnChanges, OnDestroy { this.treeService.setController(this.tree.node.id, this.controller); } - this.settings = this.settings || { rootIsVisible: true }; + + this.settings = this.settings || { rootIsVisible: true, showCheckboxes: false, enableCheckboxes: true }; + + this.isChecked = this.tree.isChecked; + + this.isReadOnly = has(this.settings, 'enableCheckboxes') ? !this.settings.enableCheckboxes : false; + this.subscriptions.push(this.nodeMenuService.hideMenuStream(this.element) .subscribe(() => { this.isRightMenuVisible = false; @@ -118,6 +140,28 @@ export class TreeInternalComponent implements OnInit, OnChanges, OnDestroy { this.moveNodeToParentTreeAndRemoveFromPreviousOne(e, this.tree); } })); + + this.subscriptions.push(this.treeService.nodeChecked$ + .filter((e: NodeCheckedEvent) => this.eventContainsId(e) && this.tree.children + && this.tree.children.some((child: Tree) => child.id === e.node.id)) + .subscribe((e: NodeCheckedEvent) => { + this.updateIndeterminateState(); + })); + + + this.subscriptions.push(this.treeService.nodeUnchecked$ + .filter((e: NodeCheckedEvent) => this.eventContainsId(e) && this.tree.children + && this.tree.children.some((child: Tree) => child.id === e.node.id)) + .subscribe((e: NodeCheckedEvent) => { + this.updateIndeterminateState(); + })); + + + this.subscriptions.push(this.treeService.nodeIndeterminate$ + .filter((e: NodeIndeterminateEvent) => this.eventContainsId(e) && + this.tree.children && this.tree.children.some((child: Tree) => child.id === e.node.id)) + .subscribe((e: NodeIndeterminateEvent) => { + })); } public ngOnChanges(changes: SimpleChanges): void { @@ -256,4 +300,84 @@ export class TreeInternalComponent implements OnInit, OnChanges, OnDestroy { public hasCustomMenu(): boolean { return this.tree.hasCustomMenu(); } + + public NodeCheckSatusChanged() { + if (!this.isChecked) { + this.onNodeChecked(); + } + else { + this.onNodeUnchecked(); + } + + } + + public onNodeChecked(): void { + this._checkboxElement.nativeElement.indeterminate = false; + this.treeService.fireNodeChecked(this.tree); + this.executeOnChildController(controller => controller.check()); + this.isChecked = true; + this.tree.isChecked = true; + } + + public onNodeUnchecked(): void { + this._checkboxElement.nativeElement.indeterminate = false; + + this.treeService.fireNodeUnchecked(this.tree); + + this.executeOnChildController(controller => controller.uncheck()); + this.isChecked = false; + this.tree.isChecked = false; + } + + private executeOnChildController(executor: (controller: TreeController) => void) { + if (this.tree.children) { + this.tree.children.forEach((child: Tree) => { + let controller = this.treeService.getController(child.id); + if (controller != null) { + executor(controller); + } + }); + } + } + + public updateIndeterminateState(): void { + + setTimeout(() => { // Calling setTimeout so the value of isChecked will be updated and after that I'll check the children status. + this.updateIndeterminateStateInternal(); + }, 1) + }; + + + private updateIndeterminateStateInternal(): void { + const checkedChildren = this.tree.children.filter(child => child.isChecked).length; + + if (checkedChildren === 0) { + this._checkboxElement.nativeElement.indeterminate = false; + this.isChecked = false; + this.tree.isChecked = false; + this.treeService.fireNodeUnchecked(this.tree) + } + else if (checkedChildren === this.tree.children.length) { + this._checkboxElement.nativeElement.indeterminate = false; + this.isChecked = true; + this.tree.isChecked = true; + this.treeService.fireNodeChecked(this.tree) + } + else { + this.setNodeInderminated(); + } + } + + private setNodeInderminated(): void { + this._checkboxElement.nativeElement.indeterminate = true; + this.treeService.fireNodeIndeterminate(this.tree); + } + + private eventContainsId(event: NodeEvent): boolean { + if (!event.node.id) { + console.log('Checking feature requires a well known id for every node, lease prvide a unique id.') + return false; + } + return true; + } } diff --git a/src/tree.component.ts b/src/tree.component.ts index c5540830..735ff7e8 100644 --- a/src/tree.component.ts +++ b/src/tree.component.ts @@ -4,7 +4,9 @@ import { } from '@angular/core'; import { TreeService } from './tree.service'; import * as TreeTypes from './tree.types'; -import { NodeEvent, MenuItemSelectedEvent } from './tree.events'; + +import { NodeEvent, NodeCheckedEvent, NodeUncheckedEvent,MenuItemSelectedEvent } from './tree.events'; + import { Tree } from './tree'; import { TreeController } from './tree-controller'; import { Subscription } from 'rxjs/Subscription'; @@ -15,7 +17,7 @@ import { Subscription } from 'rxjs/Subscription'; providers: [TreeService] }) export class TreeComponent implements OnInit, OnChanges, OnDestroy { - private static EMPTY_TREE: Tree = new Tree({value: ''}); + private static EMPTY_TREE: Tree = new Tree({ value: '' }); /* tslint:disable:no-input-rename */ @Input('tree') @@ -47,11 +49,17 @@ export class TreeComponent implements OnInit, OnChanges, OnDestroy { public nodeCollapsed: EventEmitter = new EventEmitter(); @Output() - public menuItemSelected: EventEmitter = new EventEmitter(); - @Output() public loadNextLevel: EventEmitter = new EventEmitter(); + @Output() + public nodeChecked: EventEmitter = new EventEmitter(); + + @Output() + public nodeUnchecked: EventEmitter = new EventEmitter(); + + public menuItemSelected: EventEmitter = new EventEmitter(); + public tree: Tree; @ViewChild('rootComponent') public rootComponent; @@ -59,7 +67,7 @@ export class TreeComponent implements OnInit, OnChanges, OnDestroy { private subscriptions: Subscription[] = []; - public constructor(@Inject(TreeService) private treeService: TreeService) { + public constructor( @Inject(TreeService) private treeService: TreeService) { } public ngOnChanges(changes: SimpleChanges): void { @@ -106,6 +114,11 @@ export class TreeComponent implements OnInit, OnChanges, OnDestroy { this.subscriptions.push(this.treeService.loadNextLevel$.subscribe((e: NodeEvent) => { this.loadNextLevel.emit(e); })); + + this.subscriptions.push(this.treeService.nodeChecked$.subscribe((e: NodeCheckedEvent) => this.nodeChecked.emit(e))); + + this.subscriptions.push(this.treeService.nodeUnchecked$.subscribe((e: NodeUncheckedEvent) => this.nodeChecked.emit(e))); + } public getController(): TreeController { diff --git a/src/tree.events.ts b/src/tree.events.ts index 63b3e73f..f4e317de 100644 --- a/src/tree.events.ts +++ b/src/tree.events.ts @@ -66,3 +66,21 @@ export class LoadNextLevelEvent extends NodeEvent { super(node); } } + +export class NodeCheckedEvent extends NodeEvent { + public constructor(node: Tree) { + super(node); + } +} + +export class NodeUncheckedEvent extends NodeEvent { + public constructor(node: Tree) { + super(node); + } +} + +export class NodeIndeterminateEvent extends NodeEvent { + public constructor(node: Tree) { + super(node); + } +} \ No newline at end of file diff --git a/src/tree.service.ts b/src/tree.service.ts index 44751ba9..7042b090 100644 --- a/src/tree.service.ts +++ b/src/tree.service.ts @@ -6,9 +6,11 @@ import { NodeRemovedEvent, NodeRenamedEvent, NodeSelectedEvent, + LoadNextLevelEvent, + NodeCheckedEvent, + NodeUncheckedEvent, MenuItemSelectedEvent, - LoadNextLevelEvent -} from './tree.events'; +NodeIndeterminateEvent} from './tree.events'; import { RenamableNode } from './tree.types'; import { Tree } from './tree'; import { TreeController } from './tree-controller'; @@ -30,6 +32,9 @@ export class TreeService { public nodeCollapsed$: Subject = new Subject(); public menuItemSelected$: Subject = new Subject(); public loadNextLevel$: Subject = new Subject(); + public nodeChecked$ : Subject = new Subject(); + public nodeUnchecked$ : Subject = new Subject(); + public nodeIndeterminate$ : Subject = new Subject(); private controllers: Map = new Map(); @@ -88,6 +93,14 @@ export class TreeService { this.loadNextLevel$.next(new LoadNextLevelEvent(tree)); } + public fireNodeChecked(tree: Tree) : void { + this.nodeChecked$.next(new NodeCheckedEvent(tree)); + } + + public fireNodeUnchecked(tree: Tree) : void { + this.nodeUnchecked$.next(new NodeUncheckedEvent(tree)); + } + public draggedStream(tree: Tree, element: ElementRef): Observable { return this.nodeDraggableService.draggableNodeEvents$ .filter((e: NodeDraggableEvent) => e.target === element) @@ -129,4 +142,8 @@ export class TreeService { return shouldLoadNextLevel; } + + public fireNodeIndeterminate(tree: Tree) : void { + this.nodeIndeterminate$.next(new NodeIndeterminateEvent(tree)); + } } diff --git a/src/tree.ts b/src/tree.ts index 780f4952..07f6e2e7 100644 --- a/src/tree.ts +++ b/src/tree.ts @@ -45,6 +45,7 @@ export class Tree { public node: TreeModel; public parent: Tree; + public isChecked: boolean; // STATIC METHODS ---------------------------------------------------------------------------------------------------- diff --git a/src/tree.types.ts b/src/tree.types.ts index 3633afeb..23fd1d52 100644 --- a/src/tree.types.ts +++ b/src/tree.types.ts @@ -27,6 +27,7 @@ export interface TreeModel { _status?: TreeStatus; _foldingType?: FoldingType; [additionalData: string]: any; + checked?: boolean; } export interface CssClasses { @@ -111,6 +112,8 @@ export interface Ng2TreeSettings { * @type boolean */ rootIsVisible?: boolean; + showCheckboxes?: boolean; + enableCheckboxes?: boolean; } export enum TreeStatus {