Skip to content

Commit b1124cb

Browse files
author
Georgii Rychko
authored
Merge pull request #246 from valor-software/develop
Develop
2 parents 8a096bf + 3493ff1 commit b1124cb

File tree

8 files changed

+140
-88
lines changed

8 files changed

+140
-88
lines changed

README.md

Lines changed: 86 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -6,47 +6,48 @@
66

77
<!-- TOC -->
88

9-
- [:clapper: Usage](#clapper-usage)
10-
- [:eyes: Demo](#eyes-demo)
11-
- [:wrench: API](#wrench-api)
12-
- [tree](#tree)
13-
- [[tree]](#tree)
14-
- [Load children asynchronously](#load-children-asynchronously)
15-
- [Load children using ngrx (or any redux-like library)](#load-children-using-ngrx-or-any-redux-like-library)
16-
- [Configure node via TreeModelSettings](#configure-node-via-treemodelsettings)
17-
- [[settings]](#settings)
18-
- [`Tree` class](#tree-class)
19-
- [events (nodeMoved, nodeSelected, nodeRenamed, nodeRemoved, nodeCreated, nodeExpanded, nodeCollapsed)](#events-nodemoved-nodeselected-noderenamed-noderemoved-nodecreated-nodeexpanded-nodecollapsed)
20-
- [NodeSelectedEvent](#nodeselectedevent)
21-
- [NodeMovedEvent](#nodemovedevent)
22-
- [NodeRemovedEvent](#noderemovedevent)
23-
- [NodeCreatedEvent](#nodecreatedevent)
24-
- [NodeRenamedEvent](#noderenamedevent)
25-
- [NodeExpandedEvent](#nodeexpandedevent)
26-
- [NodeCollapsedEvent](#nodecollapsedevent)
27-
- [LoadNextLevelEvent](#loadnextlevelevent)
28-
- [:gun: Controller](#gun-controller)
29-
- [select - selects a node](#select---selects-a-node)
30-
- [isSelected - checks whether a node is selected](#isselected---checks-whether-a-node-is-selected)
31-
- [collapse - collapses a node](#collapse---collapses-a-node)
32-
- [isCollapsed - check whether a node is collapsed](#iscollapsed---check-whether-a-node-is-collapsed)
33-
- [expand - expands a node](#expand---expands-a-node)
34-
- [isExpanded - checks whether a node is expanded](#isexpanded---checks-whether-a-node-is-expanded)
35-
- [toTreeModel - converts a tree to a TreeModel instance](#totreemodel---converts-a-tree-to-a-treemodel-instance)
36-
- [rename - renames a node (changes its value underneath)](#rename---renames-a-node-changes-its-value-underneath)
37-
- [startRenaming - changes the node template so that text input appears and lets a user type a new name](#startrenaming---changes-the-node-template-so-that-text-input-appears-and-lets-a-user-type-a-new-name)
38-
- [remove - removes a node from the tree](#remove---removes-a-node-from-the-tree)
39-
- [addChild - creates a new child node](#addchild---creates-a-new-child-node)
40-
- [changeNodeId - changes node's id](#changenodeid---changes-nodes-id)
41-
- [reloadChildren - loads async children once more](#reloadchildren---loads-async-children-once-more)
42-
- [setChildren - changes children of a node;](#setchildren---changes-children-of-a-node)
43-
- [SystemJS](#systemjs)
44-
- [Changes that should be taken into account in order to migrate from __ng2-tree V1__ to __ng2-tree V2__](#changes-that-should-be-taken-into-account-in-order-to-migrate-from-__ng2-tree-v1__-to-__ng2-tree-v2__)
45-
- [:bulb: Want to help?](#bulb-want-to-help)
9+
* [:clapper: Usage](#clapper-usage)
10+
* [:eyes: Demo](#eyes-demo)
11+
* [:wrench: API](#wrench-api)
12+
* [tree](#tree)
13+
* [[tree]](#tree)
14+
* [Load children asynchronously](#load-children-asynchronously)
15+
* [Load children using ngrx (or any redux-like library)](#load-children-using-ngrx-or-any-redux-like-library)
16+
* [Configure node via TreeModelSettings](#configure-node-via-treemodelsettings)
17+
* [[settings]](#settings)
18+
* [`Tree` class](#tree-class)
19+
* [events (nodeMoved, nodeSelected, nodeRenamed, nodeRemoved, nodeCreated, nodeExpanded, nodeCollapsed)](#events-nodemoved-nodeselected-noderenamed-noderemoved-nodecreated-nodeexpanded-nodecollapsed)
20+
* [NodeSelectedEvent](#nodeselectedevent)
21+
* [NodeMovedEvent](#nodemovedevent)
22+
* [NodeRemovedEvent](#noderemovedevent)
23+
* [NodeCreatedEvent](#nodecreatedevent)
24+
* [NodeRenamedEvent](#noderenamedevent)
25+
* [NodeExpandedEvent](#nodeexpandedevent)
26+
* [NodeCollapsedEvent](#nodecollapsedevent)
27+
* [LoadNextLevelEvent](#loadnextlevelevent)
28+
* [:gun: Controller](#gun-controller)
29+
* [select - selects a node](#select---selects-a-node)
30+
* [isSelected - checks whether a node is selected](#isselected---checks-whether-a-node-is-selected)
31+
* [collapse - collapses a node](#collapse---collapses-a-node)
32+
* [isCollapsed - check whether a node is collapsed](#iscollapsed---check-whether-a-node-is-collapsed)
33+
* [expand - expands a node](#expand---expands-a-node)
34+
* [isExpanded - checks whether a node is expanded](#isexpanded---checks-whether-a-node-is-expanded)
35+
* [toTreeModel - converts a tree to a TreeModel instance](#totreemodel---converts-a-tree-to-a-treemodel-instance)
36+
* [rename - renames a node (changes its value underneath)](#rename---renames-a-node-changes-its-value-underneath)
37+
* [startRenaming - changes the node template so that text input appears and lets a user type a new name](#startrenaming---changes-the-node-template-so-that-text-input-appears-and-lets-a-user-type-a-new-name)
38+
* [remove - removes a node from the tree](#remove---removes-a-node-from-the-tree)
39+
* [addChild - creates a new child node](#addchild---creates-a-new-child-node)
40+
* [changeNodeId - changes node's id](#changenodeid---changes-nodes-id)
41+
* [reloadChildren - loads async children once more](#reloadchildren---loads-async-children-once-more)
42+
* [setChildren - changes children of a node;](#setchildren---changes-children-of-a-node)
43+
* [SystemJS](#systemjs)
44+
* [Changes that should be taken into account in order to migrate from **ng2-tree V1** to **ng2-tree V2**](#changes-that-should-be-taken-into-account-in-order-to-migrate-from-__ng2-tree-v1__-to-__ng2-tree-v2__)
45+
* [:bulb: Want to help?](#bulb-want-to-help)
4646

4747
<!-- /TOC -->
4848

4949
## :clapper: Usage
50+
5051
Ok, let's start with an installation - all you need to do is:
5152

5253
`npm install --save ng2-tree`
@@ -63,11 +64,10 @@ import { TreeModule } from 'ng2-tree';
6364

6465
@NgModule({
6566
declarations: [MyComponent],
66-
imports: [BrowserModule, TreeModule],
67-
bootstrap: [MyComponent]
67+
imports: [BrowserModule, TreeModule],
68+
bootstrap: [MyComponent]
6869
})
69-
export class MyModule {
70-
}
70+
export class MyModule {}
7171
```
7272

7373
2. As soon as the previous step is done we need to give ng2-tree a model to render - this can be accomplished by populating its `[tree]` attribute with an object that conforms to the `TreeModel` interface (see [API](#wrench-api)):
@@ -88,19 +88,11 @@ class MyComponent {
8888
children: [
8989
{
9090
value: 'Object-oriented programming',
91-
children: [
92-
{value: 'Java'},
93-
{value: 'C++'},
94-
{value: 'C#'}
95-
]
91+
children: [{ value: 'Java' }, { value: 'C++' }, { value: 'C#' }]
9692
},
9793
{
9894
value: 'Prototype-based programming',
99-
children: [
100-
{value: 'JavaScript'},
101-
{value: 'CoffeeScript'},
102-
{value: 'Lua'}
103-
]
95+
children: [{ value: 'JavaScript' }, { value: 'CoffeeScript' }, { value: 'Lua' }]
10496
}
10597
]
10698
};
@@ -112,12 +104,12 @@ class MyComponent {
112104
In Angular 2/4 cli projects, modify **.angular-cli.json** as below:
113105

114106
```typescript
115-
116107
"styles": [
117108
"styles.css",
118109
"../node_modules/ng2-tree/styles.css"
119110
],
120111
```
112+
121113
4. And finally, I suppose, you'd want to listen to events generated by ng2-tree (for a full list of supported events look at the [API](#wrench-api)). No problem, this is also easy to do - for example let's add a listener for `node was selected` kind of events:
122114

123115
```typescript
@@ -138,15 +130,17 @@ class MyComponent {
138130
}
139131
}
140132
```
133+
141134
Voila! That's pretty much it - enjoy :blush:
142135

143136
## :eyes: Demo
137+
144138
Feel free to examine the [demo](https://valor-software.github.io/ng2-tree/index.html) and its [sources](src/demo) to find out how things are wired.
145139
Also, there is [another demo built with Angular CLI](https://github.com/rychkog/ng2-tree-demo).
146140

147141
## :wrench: API
148142

149-
Here is the fully stuffed *tree* tag that you can use in your templates:
143+
Here is the fully stuffed _tree_ tag that you can use in your templates:
150144

151145
```html
152146
<tree
@@ -271,7 +265,7 @@ Here is an example of such a node in the `TreeModel` object:
271265

272266
#### Load children asynchronously
273267

274-
Another worth noting thing is `loadChildren`. This function on `TreeModel` allows you to load its __children asynchronously__.
268+
Another worth noting thing is `loadChildren`. This function on `TreeModel` allows you to load its **children asynchronously**.
275269

276270
```typescript
277271
{
@@ -296,21 +290,21 @@ If `loadChildren` function is given to the node - `children` property is ignored
296290
You can also load children by changing the tree state using ngrx.
297291
The tree can emit an appropriate event notifying you to dispatch a new action in order to load the branch's children.
298292

299-
To enable this feature you should set the ```TreeModel.emitLoadNextLevel``` property to true:
293+
To enable this feature you should set the `TreeModel.emitLoadNextLevel` property to true:
300294

301-
```typscript
302-
const model: TreeModel = {
303-
emitLoadNextLevel : true
304-
}
305-
```
295+
```typscript
296+
const model: TreeModel = {
297+
emitLoadNextLevel : true
298+
}
299+
```
306300

307-
Now on the first time the node is expanded a __LoadNextLevelEvent__ will be fired (via the __loadNextLevel__ EventEmitter in the tree) containing the node that requested a next level (its children) loading.
301+
Now on the first time the node is expanded a **LoadNextLevelEvent** will be fired (via the **loadNextLevel** EventEmitter in the tree) containing the node that requested a next level (its children) loading.
308302

309303
In your code make sure you change the tree state and add the children to the model.
310304

311-
In addition the regular __NodeExpanded__ event will be fired.
305+
In addition the regular **NodeExpanded** event will be fired.
312306

313-
__NOTICE__: if both ```emitLoadNextLevel``` and ```loadChildren``` are provided, the tree will ignore the ```emitLoadNextLevel``` and the ```LoadNextLevelEvent``` won't be fired.
307+
**NOTICE**: if both `emitLoadNextLevel` and `loadChildren` are provided, the tree will ignore the `emitLoadNextLevel` and the `LoadNextLevelEvent` won't be fired.
314308

315309
#### Configure node via TreeModelSettings
316310

@@ -370,12 +364,12 @@ All options that are defined on a `parent` are automatically applied to children
370364

371365
### [settings]
372366

373-
Object that should be passed to `[settings]` must be of type [`Ng2TreeSettings`](src/tree.types.ts). This attribute is __optional__. Right now only one setting is available in there - `rootIsVisible`. This setting allows you to make a root node of the tree _invisible_:
367+
Object that should be passed to `[settings]` must be of type [`Ng2TreeSettings`](src/tree.types.ts). This attribute is **optional**. Right now only one setting is available in there - `rootIsVisible`. This setting allows you to make a root node of the tree _invisible_:
374368

375369
```typescript
376370
const treeSettings: Ng2TreeSettings = {
377371
rootIsVisible: false
378-
}
372+
};
379373
```
380374

381375
By default `rootIsVisible` equals to `true`
@@ -420,8 +414,8 @@ You can subscribe to `NodeMovedEvent` by attaching listener to `(nodeMoved)` att
420414

421415
`NodeMovedEvent` has two properties `node` and `previousParent` both of which contain `Tree` objects:
422416

423-
- `node` contains a moved node;
424-
- `previousParent` contains a previous parent of the moved node;
417+
* `node` contains a moved node;
418+
* `previousParent` contains a previous parent of the moved node;
425419

426420
```typescript
427421
{node: <Tree>{...}, previousParent: <Tree>{...}}
@@ -474,9 +468,9 @@ You can subscribe to `NodeRenamedEvent` by attaching listener to `(nodeRenamed)`
474468

475469
`NodeRenamedEvent` has three properties:
476470

477-
- `node` contains a node that was renamed ( an instance of `Tree`).
478-
- `oldValue` contains a value, that node used to have (it might be `string` or `RenamableNode`)
479-
- `newValue` contains a new value of the node (it might be `string` or `RenamableNode`)
471+
* `node` contains a node that was renamed ( an instance of `Tree`).
472+
* `oldValue` contains a value, that node used to have (it might be `string` or `RenamableNode`)
473+
* `newValue` contains a new value of the node (it might be `string` or `RenamableNode`)
480474

481475
```typescript
482476
{
@@ -539,6 +533,7 @@ Relevant for loading children via ngrx (or any redux-inspired library).
539533
```
540534

541535
## :gun: Controller
536+
542537
First of all you should know how to get a controller of a particular node. You can get a controller of a node only if you set an id property of a node.
543538

544539
> TIP: Ids for nodes created via the context menu or using a TreeController instance get populated automatically unless nodes had ids before there were added to the tree
@@ -661,6 +656,16 @@ oopNodeController.expand();
661656

662657
This method expands the node in case it can be expanded. On successful expanding the expand event is fired.
663658

659+
#### expandToParent - expands a node and its parents up to the root
660+
661+
```typescript
662+
oopNodeController.expandToParent();
663+
```
664+
665+
This method expands the node even if it is a leaf. Expand event is fired for every expanded parent up to the root.
666+
667+
**Important:** For this to work - `keepNodesInDOM: true` should be set on the appropriate tree.
668+
664669
#### isExpanded - checks whether a node is expanded
665670

666671
```typescript
@@ -731,16 +736,17 @@ oopNodeController.reloadChildren();
731736

732737
```typescript
733738
let newChildren: Array<TreeModel> = [
734-
{value: 'new children 1'},
735-
{value: 'new children 2'},
736-
{value: 'new children 3'}
739+
{ value: 'new children 1' },
740+
{ value: 'new children 2' },
741+
{ value: 'new children 3' }
737742
];
738743
oopNodeController.setChildren(newChildren);
739744
```
740745

741746
This method replaces all existing children of the node with new ones.
742747

743748
## SystemJS
749+
744750
If you are using SystemJS, then you need
745751

746752
```javascript
@@ -755,12 +761,13 @@ System.config({
755761
}
756762
```
757763
758-
## Changes that should be taken into account in order to migrate from __ng2-tree V1__ to __ng2-tree V2__
759-
- Events were reworked:
760-
- In V1 all events that were inherited from NodeDestructiveEvent used to have property `parent`. It's not the case anymore. If you need a parent you should get it from `node` in event object like `node.parent`;
761-
- All events used to have `node` property of type `TreeModel`. Now `node` is of type [Tree](#tree-class) (as well as `node.parent`);
762-
- `NodeMovedEvent` now has property `previousParent`, which contains tree in which moved node used to be.
763-
- CSS styles in __ng2-tree V2__ are distributed as separate file which you can find in `node_modules/ng2-tree/styles.css`. That allows you to override ng2-tree styles more easily.
764+
## Changes that should be taken into account in order to migrate from **ng2-tree V1** to **ng2-tree V2**
765+
766+
* Events were reworked:
767+
* In V1 all events that were inherited from NodeDestructiveEvent used to have property `parent`. It's not the case anymore. If you need a parent you should get it from `node` in event object like `node.parent`;
768+
* All events used to have `node` property of type `TreeModel`. Now `node` is of type [Tree](#tree-class) (as well as `node.parent`);
769+
* `NodeMovedEvent` now has property `previousParent`, which contains tree in which moved node used to be.
770+
* CSS styles in **ng2-tree V2** are distributed as separate file which you can find in `node_modules/ng2-tree/styles.css`. That allows you to override ng2-tree styles more easily.
764771
765772
## :bulb: Want to help?
766773

src/demo/app/app.component.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ declare const alertify: any;
6666
6767
<div class="tree-controlls">
6868
<p class="notice">Tree API exposed via TreeController</p>
69+
<button button (click)="handleActionOnFFS(21, 'expandToParent')">Select 'unicode.pf2' up to root</button>
6970
<button button (click)="handleActionOnFFS(13, 'select')">Select 'boot' node</button>
7071
<button button (click)="handleActionOnFFS(13, 'unselect')">Unselect 'boot' node</button>
7172
<button button (click)="handleActionOnFFS(13, 'allowSelection')">Allow selection of the 'boot' node</button>
@@ -314,6 +315,10 @@ export class AppComponent implements OnInit {
314315
{
315316
value: 'boot',
316317
id: 13,
318+
settings: {
319+
isCollapsedOnInit: true,
320+
keepNodesInDOM: true
321+
},
317322
children: [
318323
{
319324
value: 'grub',

src/tree-controller.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,16 @@ export class TreeController {
3737
}
3838
}
3939

40+
public expandToParent(tree: any = this.tree): void {
41+
if (tree) {
42+
const controller = this.treeService.getController(tree.id);
43+
if (controller) {
44+
controller.expand();
45+
this.expandToParent(tree.parent);
46+
}
47+
}
48+
}
49+
4050
public isExpanded(): boolean {
4151
return this.tree.isNodeExpanded();
4252
}

src/tree-internal.component.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,11 @@ import { get, isNil } from './utils/fn.utils';
7373
[menuItems]="tree.menuItems"
7474
(menuItemSelected)="onMenuItemSelected($event)">
7575
</node-menu>
76-
<ng-template [ngIf]="tree.isNodeExpanded()">
76+
77+
<div *ngIf="tree.keepNodesInDOM()" [ngStyle]="{'display': tree.isNodeExpanded() ? 'block' : 'none'}">
78+
<tree-internal *ngFor="let child of tree.childrenAsync | async" [tree]="child" [template]="template" [settings]="settings"></tree-internal>
79+
</div>
80+
<ng-template [ngIf]="tree.isNodeExpanded() && !tree.keepNodesInDOM()">
7781
<tree-internal *ngFor="let child of tree.childrenAsync | async" [tree]="child" [template]="template" [settings]="settings"></tree-internal>
7882
</ng-template>
7983
</li>

src/tree.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,10 @@ export class Tree {
583583
return !!get(this.node.settings, 'isCollapsedOnInit');
584584
}
585585

586+
public keepNodesInDOM() {
587+
return get(this.node.settings, 'keepNodesInDOM');
588+
}
589+
586590
/**
587591
* Check that current tree is newly created (added by user via menu for example). Tree that was built from the TreeModel is not marked as new.
588592
* @returns {boolean} A flag whether the tree is new.

src/tree.types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ export class TreeModelSettings {
9797

9898
public selectionAllowed?: boolean;
9999

100+
public keepNodesInDOM?: boolean;
101+
100102
public static readonly NOT_CASCADING_SETTINGS = ['selectionAllowed'];
101103

102104
public static merge(child: TreeModel, parent: TreeModel): TreeModelSettings {
@@ -107,6 +109,7 @@ export class TreeModelSettings {
107109
rightMenu: true,
108110
isCollapsedOnInit: false,
109111
checked: false,
112+
keepNodesInDOM: false,
110113
selectionAllowed: true
111114
});
112115
}

0 commit comments

Comments
 (0)